|
|
@ -10,16 +10,18 @@ |
|
|
|
|
|
|
|
|
|
|
|
mod data; |
|
|
|
mod data; |
|
|
|
mod date; |
|
|
|
mod date; |
|
|
|
mod error; |
|
|
|
|
|
|
|
mod format; |
|
|
|
mod format; |
|
|
|
pub mod meta; |
|
|
|
|
|
|
|
mod time; |
|
|
|
mod time; |
|
|
|
mod timeline; |
|
|
|
mod timeline; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub mod error; |
|
|
|
|
|
|
|
pub mod meta; |
|
|
|
|
|
|
|
|
|
|
|
pub use date::Date; |
|
|
|
pub use date::Date; |
|
|
|
pub use time::Time; |
|
|
|
pub use time::Time; |
|
|
|
|
|
|
|
|
|
|
|
use data::{Invoice, Session, TimeFile}; |
|
|
|
use data::{Invoice, Session, TimeFile}; |
|
|
|
|
|
|
|
use error::{ParseError, ParseResult}; |
|
|
|
use format::{ |
|
|
|
use format::{ |
|
|
|
ir::{append_ir, clean_ir, IrStream, MakeIr}, |
|
|
|
ir::{append_ir, clean_ir, IrStream, MakeIr}, |
|
|
|
ParseOutput, |
|
|
|
ParseOutput, |
|
|
@ -36,27 +38,22 @@ pub struct Cassiopeia { |
|
|
|
|
|
|
|
|
|
|
|
impl Cassiopeia { |
|
|
|
impl Cassiopeia { |
|
|
|
/// Load a cass file from disk, parsing it into a [`TimeFile`](crate::TimeFile)
|
|
|
|
/// Load a cass file from disk, parsing it into a [`TimeFile`](crate::TimeFile)
|
|
|
|
pub fn load(path: &str) -> Option<Self> { |
|
|
|
pub fn load(path: &str) -> ParseResult<Self> { |
|
|
|
let path = path.to_owned(); |
|
|
|
let path = path.to_owned(); |
|
|
|
format::load_file(path.as_str()).map(|ParseOutput { tf, ir }| Self { path, tf, ir }) |
|
|
|
format::load_file(path.as_str()).map(|ParseOutput { tf, ir }| Self { path, tf, ir }) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Store the modified time file back to disk
|
|
|
|
|
|
|
|
pub fn store(&self) -> Option<()> { |
|
|
|
|
|
|
|
Some(()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Start a new work session (with optional 15 minute rounding)
|
|
|
|
/// Start a new work session (with optional 15 minute rounding)
|
|
|
|
pub fn start(&mut self, round: bool) -> Option<()> { |
|
|
|
pub fn start(&mut self, round: bool) -> ParseResult<()> { |
|
|
|
let delta = self.tf.timeline.start(Time::rounded(round)).ok()?; |
|
|
|
let delta = self.tf.timeline.start(Time::rounded(round))?; |
|
|
|
clean_ir(&mut self.ir); |
|
|
|
clean_ir(&mut self.ir); |
|
|
|
append_ir(&mut self.ir, delta.make_ir()); |
|
|
|
append_ir(&mut self.ir, delta.make_ir()); |
|
|
|
format::write_file(self.path.as_str(), &mut self.ir) |
|
|
|
format::write_file(self.path.as_str(), &mut self.ir) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Stop the existing work session (with optional 15 minute rounding)
|
|
|
|
/// Stop the existing work session (with optional 15 minute rounding)
|
|
|
|
pub fn stop(&mut self, round: bool) -> Option<()> { |
|
|
|
pub fn stop(&mut self, round: bool) -> ParseResult<()> { |
|
|
|
let delta = self.tf.timeline.stop(Time::rounded(round)).ok()?; |
|
|
|
let delta = self.tf.timeline.stop(Time::rounded(round))?; |
|
|
|
clean_ir(&mut self.ir); |
|
|
|
clean_ir(&mut self.ir); |
|
|
|
append_ir(&mut self.ir, delta.make_ir()); |
|
|
|
append_ir(&mut self.ir, delta.make_ir()); |
|
|
|
format::write_file(self.path.as_str(), &mut self.ir) |
|
|
|
format::write_file(self.path.as_str(), &mut self.ir) |
|
|
@ -68,14 +65,14 @@ impl Cassiopeia { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Write out the file IR as is, updating only the header version
|
|
|
|
/// Write out the file IR as is, updating only the header version
|
|
|
|
pub fn update(&mut self) -> Option<()> { |
|
|
|
pub fn update(&mut self) -> ParseResult<()> { |
|
|
|
clean_ir(&mut self.ir); |
|
|
|
clean_ir(&mut self.ir); |
|
|
|
format::write_file(self.path.as_str(), &mut self.ir) |
|
|
|
format::write_file(self.path.as_str(), &mut self.ir) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Collect statistics on previous work sessions
|
|
|
|
/// Collect statistics on previous work sessions
|
|
|
|
pub fn stat(&self) -> Option<String> { |
|
|
|
pub fn stat(&self) -> ParseResult<String> { |
|
|
|
None |
|
|
|
todo!() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -102,6 +99,7 @@ impl Cassiopeia { |
|
|
|
/// .client("ACME".into())
|
|
|
|
/// .client("ACME".into())
|
|
|
|
/// .run();
|
|
|
|
/// .run();
|
|
|
|
/// ```
|
|
|
|
/// ```
|
|
|
|
|
|
|
|
#[allow(unused)] |
|
|
|
pub struct Invoicer<'cass> { |
|
|
|
pub struct Invoicer<'cass> { |
|
|
|
tf: &'cass mut Cassiopeia, |
|
|
|
tf: &'cass mut Cassiopeia, |
|
|
|
generate: bool, |
|
|
|
generate: bool, |
|
|
@ -143,13 +141,13 @@ impl<'cass> Invoicer<'cass> { |
|
|
|
Self { project, ..self } |
|
|
|
Self { project, ..self } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn run(mut self) -> Option<()> { |
|
|
|
pub fn run(mut self) -> ParseResult<()> { |
|
|
|
if self.generate { |
|
|
|
if self.generate { |
|
|
|
eprintln!("Integration with invoice(1) is currently not implemented. Sorry :("); |
|
|
|
eprintln!("Integration with invoice(1) is currently not implemented. Sorry :("); |
|
|
|
return None; |
|
|
|
return Err(ParseError::Unknown); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let delta = self.tf.tf.timeline.invoice(Date::today()).ok()?; |
|
|
|
let delta = self.tf.tf.timeline.invoice(Date::today())?; |
|
|
|
clean_ir(&mut self.tf.ir); |
|
|
|
clean_ir(&mut self.tf.ir); |
|
|
|
append_ir(&mut self.tf.ir, delta.make_ir()); |
|
|
|
append_ir(&mut self.tf.ir, delta.make_ir()); |
|
|
|
format::write_file(self.tf.path.as_str(), &mut self.tf.ir) |
|
|
|
format::write_file(self.tf.path.as_str(), &mut self.tf.ir) |
|
|
|