From b476a95afba963ae300bea407a84b93b842cca44 Mon Sep 17 00:00:00 2001 From: Joscha Date: Tue, 14 Dec 2021 22:37:27 +0100 Subject: [PATCH] Implement done command --- src/cli.rs | 15 ++++++--------- src/cli/done.rs | 16 ++++++++++++++++ src/cli/error.rs | 3 +++ src/cli/show.rs | 13 +++---------- src/eval/date.rs | 24 ++++++++++++++++++++++++ src/files.rs | 16 +++++++++++++++- 6 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 src/cli/done.rs diff --git a/src/cli.rs b/src/cli.rs index ddf7c7c..43d0724 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,5 +1,4 @@ use std::path::PathBuf; -use std::process; use chrono::{Duration, NaiveDate}; use directories::ProjectDirs; @@ -8,8 +7,9 @@ use structopt::StructOpt; use crate::eval::{DateRange, EntryMode}; use crate::files::Files; -use self::error::Result; +use self::error::{Error, Result}; +mod done; mod error; mod layout; mod show; @@ -75,15 +75,12 @@ pub fn run() -> Result<()> { match opt.command { None | Some(Command::Show) => match opt.entry { - None => print!("{}", show::show_all(&layout)), - Some(n) => show::show_entry(&files, &entries, &layout, n)?, + None => show::show_all(&layout), + Some(n) => show::show_entry(&files, &entries[layout.look_up_number(n)?])?, }, Some(Command::Done) => match opt.entry { - None => { - println!("Please specify an entry. See `today --help` for more details."); - process::exit(1); - } - Some(i) => todo!(), + None => return Err(Error::NoNumber), + Some(n) => done::mark_done(&mut files, &entries[layout.look_up_number(n)?], now)?, }, Some(Command::Fmt) => files.mark_all_dirty(), } diff --git a/src/cli/done.rs b/src/cli/done.rs new file mode 100644 index 0000000..b888f55 --- /dev/null +++ b/src/cli/done.rs @@ -0,0 +1,16 @@ +use chrono::NaiveDateTime; + +use crate::eval::Entry; +use crate::files::commands::Done; +use crate::files::Files; + +use super::error::Result; + +pub fn mark_done(files: &mut Files, entry: &Entry, now: NaiveDateTime) -> Result<()> { + let done = Done { + date: entry.dates.map(|dates| dates.into()), + done_at: now.date(), + }; + files.add_done(entry.source, done)?; + Ok(()) +} diff --git a/src/cli/error.rs b/src/cli/error.rs index 944bb55..8d0a0a8 100644 --- a/src/cli/error.rs +++ b/src/cli/error.rs @@ -1,5 +1,6 @@ use std::result; +use crate::files::Source; use crate::{eval, files}; #[derive(Debug, thiserror::Error)] @@ -8,6 +9,8 @@ pub enum Error { Files(#[from] files::Error), #[error("{0}")] Eval(#[from] eval::Error), + #[error("No number specified")] + NoNumber, #[error("No entry with number {0}")] NoSuchEntry(usize), } diff --git a/src/cli/show.rs b/src/cli/show.rs index 0dab952..c93e971 100644 --- a/src/cli/show.rs +++ b/src/cli/show.rs @@ -115,23 +115,16 @@ impl ShowLines { } } -pub fn show_all(layout: &LineLayout) -> String { +pub fn show_all(layout: &LineLayout) { let num_width = cmp::max(layout.num_width(), 3); // `now` is 3 chars wide let mut show_lines = ShowLines::new(num_width, layout.span_width()); for line in layout.lines() { show_lines.display_line(line); } - show_lines.result() + print!("{}", show_lines.result()); } -pub fn show_entry( - files: &Files, - entries: &[Entry], - layout: &LineLayout, - number: usize, -) -> Result<()> { - let index = layout.look_up_number(number)?; - let entry = &entries[index]; +pub fn show_entry(files: &Files, entry: &Entry) -> Result<()> { let command = files.command(entry.source); match entry.kind { diff --git a/src/eval/date.rs b/src/eval/date.rs index 762cd2b..c2db627 100644 --- a/src/eval/date.rs +++ b/src/eval/date.rs @@ -37,6 +37,30 @@ impl fmt::Display for Dates { } } +impl From for DoneDate { + fn from(dates: Dates) -> Self { + match dates.times { + Some(times) if dates.root == dates.other && times.root == times.other => { + DoneDate::DateWithTime { + root: dates.root, + root_time: times.root, + } + } + Some(times) => DoneDate::DateToDateWithTime { + root: dates.root, + root_time: times.root, + other: dates.other, + other_time: times.other, + }, + None if dates.root == dates.other => DoneDate::Date { root: dates.root }, + None => DoneDate::DateToDate { + root: dates.root, + other: dates.other, + }, + } + } +} + impl Dates { pub fn new(root: NaiveDate, other: NaiveDate) -> Self { Self { diff --git a/src/files.rs b/src/files.rs index bea36a3..82af23e 100644 --- a/src/files.rs +++ b/src/files.rs @@ -5,7 +5,7 @@ use std::{fs, io, result}; use chrono::{DateTime, Utc}; use tzfile::Tz; -use self::commands::{Command, File}; +use self::commands::{Command, Done, File}; pub mod commands; mod format; @@ -79,6 +79,9 @@ pub enum Error { file2: PathBuf, tz2: String, }, + // TODO Add span or something similar for a nicer error message + #[error("Not a task")] + NotATask, } pub type Result = result::Result; @@ -161,6 +164,7 @@ impl Files { pub fn save(&self) -> Result<()> { for file in &self.files { if file.dirty { + println!("Saving file {:?}", file.path); Self::save_file(&file.path, &file.file)?; } } @@ -185,6 +189,16 @@ impl Files { &self.files[source.file].file.commands[source.command] } + pub fn add_done(&mut self, source: Source, done: Done) -> Result<()> { + let file = &mut self.files[source.file]; + match &mut file.file.commands[source.command] { + Command::Task(t) => t.done.push(done), + Command::Note(_) => return Err(Error::NotATask), + } + file.dirty = true; + Ok(()) + } + pub fn commands(&self) -> Vec> { let mut result = vec![]; for (file_index, file) in self.files.iter().enumerate() {