diff --git a/src/cli.rs b/src/cli.rs index 10b4e36..d1d9005 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -7,20 +7,19 @@ use codespan_reporting::files::SimpleFile; use directories::ProjectDirs; use structopt::StructOpt; -use crate::error; -// use crate::eval::{DateRange, Entry, EntryMode, SourceInfo}; +use crate::eval::{DateRange, Entry, EntryMode}; use crate::files::arguments::Range; -use crate::files::{self, Files}; +use crate::files::{self, FileSource, Files}; -// use self::error::Result; -// use self::layout::line::LineLayout; +use self::error::Error; +use self::layout::line::LineLayout; -// mod cancel; -// mod done; -// mod error; -// mod layout; -// mod print; -// mod show; +mod cancel; +mod done; +mod error; +mod layout; +mod print; +mod show; #[derive(Debug, StructOpt)] pub struct Opt { @@ -83,9 +82,7 @@ fn find_now(opt: &Opt, files: &Files) -> NaiveDateTime { } } -/* - -fn find_entries(files: &Files, range: DateRange) -> Result> { +fn find_entries(files: &Files, range: DateRange) -> Result, Error> { Ok(files.eval(EntryMode::Relevant, range)?) } @@ -98,7 +95,12 @@ fn find_layout( layout::layout(files, entries, range, now) } -fn run_command(opt: &Opt, files: &mut Files, range: DateRange, now: NaiveDateTime) -> Result<()> { +fn run_command( + opt: &Opt, + files: &mut Files, + range: DateRange, + now: NaiveDateTime, +) -> Result<(), Error> { match &opt.command { None => { let entries = find_entries(files, range)?; @@ -131,14 +133,12 @@ fn run_command(opt: &Opt, files: &mut Files, range: DateRange, now: NaiveDateTim Ok(()) } -*/ - pub fn run() { let opt = Opt::from_args(); let mut files = Files::new(); if let Err(e) = load_files(&opt, &mut files) { - error::eprint_error(&files, &e); + crate::error::eprint_error(&files, &e); process::exit(1); } @@ -151,7 +151,7 @@ pub fn run() { Err(e) => { eprintln!("Failed to evaluate --range:"); let file = SimpleFile::new("--range", &opt.range); - error::eprint_error(&file, &e); + crate::error::eprint_error(&file, &e); process::exit(1) } }, @@ -161,17 +161,13 @@ pub fn run() { } }; - /* - if let Err(e) = run_command(&opt, &mut files, range, now) { - e.print(&files.sources()); + crate::error::eprint_error(&files, &e); process::exit(1); } - */ - if let Err(e) = files.save() { - error::eprint_error(&files, &e); + crate::error::eprint_error(&files, &e); process::exit(1); } } diff --git a/src/cli/cancel.rs b/src/cli/cancel.rs index 62cc8ea..4821676 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, Result}; +use super::error::Error; use super::layout::line::LineLayout; -pub fn cancel( +pub fn cancel( files: &mut Files, entries: &[Entry], layout: &LineLayout, numbers: &[usize], now: NaiveDateTime, -) -> Result<()> { +) -> Result<(), Error> { 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 1d3d809..d68ad38 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, Result}; +use super::error::Error; use super::layout::line::LineLayout; -pub fn done( +pub fn done( files: &mut Files, entries: &[Entry], layout: &LineLayout, numbers: &[usize], now: NaiveDateTime, -) -> Result<()> { +) -> Result<(), Error> { 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 3bf054e..725b2e3 100644 --- a/src/cli/error.rs +++ b/src/cli/error.rs @@ -1,21 +1,25 @@ use std::result; -use crate::eval::{self, SourceInfo}; +use codespan_reporting::files::Files; +use codespan_reporting::term::Config; + +use crate::error::Eprint; +use crate::eval; #[derive(Debug, thiserror::Error)] -pub enum Error { +pub enum Error { #[error("{0}")] - Eval(#[from] eval::Error), + Eval(#[from] eval::Error), #[error("No entry with number {0}")] NoSuchEntry(usize), #[error("Not a task")] NotATask(Vec), } -impl Error { - pub fn print<'a>(&self, sources: &[SourceInfo<'a>]) { +impl<'a, F: Files<'a>> Eprint<'a, F> for Error { + fn eprint<'f: 'a>(&self, files: &'f F, config: &Config) { match self { - Error::Eval(e) => e.print(sources), + Error::Eval(e) => e.eprint(files, config), Error::NoSuchEntry(n) => eprintln!("No entry with number {}", n), Error::NotATask(ns) => { if ns.is_empty() { @@ -30,5 +34,3 @@ impl Error { } } } - -pub type Result = result::Result; diff --git a/src/cli/layout/day.rs b/src/cli/layout/day.rs index 30db056..f3866a3 100644 --- a/src/cli/layout/day.rs +++ b/src/cli/layout/day.rs @@ -8,7 +8,6 @@ use std::collections::HashMap; use chrono::{NaiveDate, NaiveDateTime}; use crate::eval::{DateRange, Dates, Entry, EntryKind}; -use crate::files::commands::Command; use crate::files::primitives::Time; use crate::files::Files; @@ -51,15 +50,10 @@ impl DayLayout { pub fn layout(&mut self, files: &Files, entries: &[Entry]) { self.insert(self.today, DayEntry::Now(self.time)); - let mut commands = entries - .iter() - .enumerate() - .map(|(i, e)| (i, e, files.command(e.source))) - .collect::>(); + let mut entries = entries.iter().enumerate().collect::>(); + Self::sort_entries(&mut entries); - Self::sort_entries(&mut commands); - - for (index, entry, _) in commands { + for (index, entry) in entries { self.layout_entry(index, entry); } @@ -196,7 +190,7 @@ impl DayLayout { } } - fn sort_entries(entries: &mut Vec<(usize, &Entry, &Command)>) { + fn sort_entries(entries: &mut Vec<(usize, &Entry)>) { // Entries should be sorted by these factors, in descending order of // significance: // 1. Their start date, if any @@ -205,10 +199,10 @@ impl DayLayout { // 4. Their title // 4. - entries.sort_by_key(|(_, _, c)| c.title()); + entries.sort_by_key(|(_, e)| &e.title); // 3. - entries.sort_by_key(|(_, e, _)| match e.kind { + entries.sort_by_key(|(_, e)| match e.kind { EntryKind::Task => 0, EntryKind::TaskDone(_) | EntryKind::TaskCanceled(_) => 1, EntryKind::Birthday(_) => 2, @@ -216,14 +210,14 @@ impl DayLayout { }); // 2. - entries.sort_by(|(_, e1, _), (_, e2, _)| { + entries.sort_by(|(_, e1), (_, e2)| { let d1 = e1.dates.map(|d| d.sorted().other_with_time()); let d2 = e2.dates.map(|d| d.sorted().other_with_time()); d2.cmp(&d1) // Inverse comparison }); // 1. - entries.sort_by_key(|(_, e, _)| e.dates.map(|d| d.sorted().root_with_time())); + entries.sort_by_key(|(_, e)| e.dates.map(|d| d.sorted().root_with_time())); } fn sort_day(day: &mut Vec) { diff --git a/src/cli/layout/line.rs b/src/cli/layout/line.rs index 637d963..78bbabc 100644 --- a/src/cli/layout/line.rs +++ b/src/cli/layout/line.rs @@ -11,7 +11,7 @@ use crate::eval::{Entry, EntryKind}; use crate::files::primitives::Time; use crate::files::Files; -use super::super::error::{Error, Result}; +use super::super::error::Error; use super::day::{DayEntry, DayLayout}; #[derive(Debug, Clone, Copy)] @@ -145,7 +145,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) @@ -253,10 +253,10 @@ impl LineLayout { } fn entry_title(files: &Files, entry: &Entry) -> String { - let command = files.command(entry.source); + let command = files.command(entry.source).command; match entry.kind { - EntryKind::Birthday(Some(age)) => format!("{} ({})", command.title(), age), - _ => command.title().to_string(), + EntryKind::Birthday(Some(age)) => format!("{} ({})", entry.title, age), + _ => entry.title.clone(), } } diff --git a/src/cli/show.rs b/src/cli/show.rs index 81cac22..1b433eb 100644 --- a/src/cli/show.rs +++ b/src/cli/show.rs @@ -1,32 +1,18 @@ use crate::eval::{Entry, EntryKind}; use crate::files::Files; -use super::error::Result; +use super::error::Error; use super::layout::line::LineLayout; fn show_entry(files: &Files, entry: &Entry) { let command = files.command(entry.source); - match entry.kind { - EntryKind::Task => println!("TASK {}", command.title()), - EntryKind::TaskDone(when) => { - println!("DONE {}", command.title()); - println!("DONE AT {}", when); - } - EntryKind::TaskCanceled(when) => { - println!("CANCELED {}", command.title()); - println!("CANCELED AT {}", when); - } - EntryKind::Note => println!("NOTE {}", command.title()), - EntryKind::Birthday(Some(age)) => { - println!("BIRTHDAY {}", command.title()); - println!("AGE {}", age); - } - EntryKind::Birthday(None) => { - println!("BIRTHDAY {}", command.title()); - println!("AGE UNKNOWN"); - } - } + let kind = match entry.kind { + EntryKind::Task | EntryKind::TaskDone(_) | EntryKind::TaskCanceled(_) => "TASK", + EntryKind::Note => "NOTE", + EntryKind::Birthday(_) => "BIRTHDAY", + }; + println!("{} {}", kind, entry.title); if let Some(dates) = entry.dates { println!("DATE {}", dates.sorted()); @@ -34,17 +20,25 @@ fn show_entry(files: &Files, entry: &Entry) { println!("NO DATE"); } - for line in command.desc() { - println!("# {}", line); + match entry.kind { + EntryKind::TaskDone(when) => println!("DONE {}", when), + EntryKind::TaskCanceled(when) => println!("CANCELED {}", when), + EntryKind::Birthday(Some(age)) => println!("AGE {}", age), + _ => {} + } + + println!("FROM COMMAND"); + for line in format!("{}", command.command).lines() { + println!("| {}", line); } } -pub fn show( +pub fn show( files: &Files, entries: &[Entry], layout: &LineLayout, numbers: &[usize], -) -> Result<()> { +) -> Result<(), Error> { if numbers.is_empty() { // Nothing to do return Ok(()); @@ -53,7 +47,7 @@ pub fn show( let indices = numbers .iter() .map(|n| layout.look_up_number(*n)) - .collect::>>()?; + .collect::, _>>()?; show_entry(files, &entries[indices[0]]); for &index in indices.iter().skip(1) { diff --git a/src/eval/command.rs b/src/eval/command.rs index e50e580..0bec665 100644 --- a/src/eval/command.rs +++ b/src/eval/command.rs @@ -45,6 +45,20 @@ impl<'a> EvalCommand<'a> { } } + fn title(&self) -> String { + match self { + Self::Task(task) => task.title.clone(), + Self::Note(note) => note.title.clone(), + } + } + + fn has_description(&self) -> bool { + match self { + Self::Task(task) => !task.desc.is_empty(), + Self::Note(note) => !note.desc.is_empty(), + } + } + /// Last root date mentioned in any `DONE`. fn last_done_root(&self) -> Option { match self { @@ -172,7 +186,14 @@ impl<'a> CommandState<'a> { None }; - Ok(Entry::new(self.source, kind, dates, remind)) + Ok(Entry::new( + self.source, + kind, + self.command.title(), + self.command.has_description(), + dates, + remind, + )) } /// Add an entry, respecting [`Self::from`] and [`Self::until`]. Does not diff --git a/src/eval/entry.rs b/src/eval/entry.rs index 09d51a0..f0f1e74 100644 --- a/src/eval/entry.rs +++ b/src/eval/entry.rs @@ -15,10 +15,12 @@ pub enum EntryKind { } /// A single instance of a command. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone)] pub struct Entry { pub source: Source, pub kind: EntryKind, + pub title: String, + pub has_description: bool, pub dates: Option, /// Remind the user of an entry before it occurs. This date should always be /// before the entry's start date, or `None` if there is no start date. @@ -29,6 +31,8 @@ impl Entry { pub fn new( source: Source, kind: EntryKind, + title: String, + has_description: bool, dates: Option, remind: Option, ) -> Self { @@ -43,6 +47,8 @@ impl Entry { Self { source, kind, + title, + has_description, dates, remind, } diff --git a/src/files.rs b/src/files.rs index 3ba0573..484c76b 100644 --- a/src/files.rs +++ b/src/files.rs @@ -7,7 +7,7 @@ use chrono::{DateTime, NaiveDate, Utc}; use codespan_reporting::files::SimpleFiles; use tzfile::Tz; -use self::commands::{Command, File}; +use self::commands::{Command, Done, File}; pub use self::error::{Error, Result}; use self::primitives::Spanned; @@ -337,7 +337,6 @@ impl Files { } } - /* /// Add a [`Done`] statement to the task identified by `source`. /// /// Returns whether the addition was successful. It can fail if the entry @@ -347,12 +346,11 @@ impl Files { let file = &mut self.files[source.file]; match &mut file.file.commands[source.command] { Command::Task(t) => t.done.push(done), - Command::Note(_) => return false, + _ => return false, } file.dirty = true; true } - */ /* Errors */