Implement done command
This commit is contained in:
parent
0de89bd424
commit
b476a95afb
6 changed files with 67 additions and 20 deletions
15
src/cli.rs
15
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(),
|
||||
}
|
||||
|
|
|
|||
16
src/cli/done.rs
Normal file
16
src/cli/done.rs
Normal file
|
|
@ -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(())
|
||||
}
|
||||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,30 @@ impl fmt::Display for Dates {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Dates> 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 {
|
||||
|
|
|
|||
16
src/files.rs
16
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<T> = result::Result<T, Error>;
|
||||
|
|
@ -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<SourcedCommand<'_>> {
|
||||
let mut result = vec![];
|
||||
for (file_index, file) in self.files.iter().enumerate() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue