Change commands to a more statement-driven format
This commit is contained in:
parent
f42027e378
commit
b5ef9e8134
6 changed files with 181 additions and 212 deletions
|
|
@ -58,18 +58,17 @@ DATE 0016-04-09 +dsun; +19y
|
||||||
DATE 0017-03-29 +dsun; +19y
|
DATE 0017-03-29 +dsun; +19y
|
||||||
DATE 0018-04-17 +dsun; +19y
|
DATE 0018-04-17 +dsun; +19y
|
||||||
|
|
||||||
BIRTHDAY Max
|
NOTE Max
|
||||||
BDATE 1987-05-14
|
BDATE 1987-05-14
|
||||||
|
|
||||||
BIRTHDAY Martha
|
NOTE Martha
|
||||||
BDATE ?-09-21
|
BDATE ?-09-21
|
||||||
|
|
||||||
NOTE Physics lecture
|
NOTE Physics lecture
|
||||||
DATE wed 14:00 -- 15:30
|
|
||||||
DATE 2021-05-07 14:00 -- 15:30
|
|
||||||
FROM 2021-04-14
|
FROM 2021-04-14
|
||||||
UNTIL 2021-07-28
|
UNTIL 2021-07-28
|
||||||
EXCEPT 2021-05-06
|
DATE wed 14:00 -- 15:30
|
||||||
|
MOVE 2021-05-06 TO 2021-05-07
|
||||||
# This is a description of the event. It might mention further information that
|
# This is a description of the event. It might mention further information that
|
||||||
# doesn't fit into the title.
|
# doesn't fit into the title.
|
||||||
#
|
#
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,22 @@ pub enum Spec {
|
||||||
Formula(FormulaSpec),
|
Formula(FormulaSpec),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BirthdaySpec {
|
||||||
|
pub date: NaiveDate,
|
||||||
|
pub year_known: bool, // If year is unknown, use NaiveDate of year 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Statement {
|
||||||
|
Date(Spec),
|
||||||
|
BDate(BirthdaySpec),
|
||||||
|
From(Option<NaiveDate>),
|
||||||
|
Until(Option<NaiveDate>),
|
||||||
|
Except(NaiveDate), // TODO Allow excluding ranges
|
||||||
|
Move(NaiveDate, NaiveDate),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum DoneDate {
|
pub enum DoneDate {
|
||||||
Date {
|
Date {
|
||||||
|
|
@ -406,10 +422,7 @@ pub struct Done {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub when: Vec<Spec>,
|
pub statements: Vec<Statement>,
|
||||||
pub from: Option<NaiveDate>,
|
|
||||||
pub until: Option<NaiveDate>,
|
|
||||||
pub except: Vec<NaiveDate>,
|
|
||||||
pub done: Vec<Done>,
|
pub done: Vec<Done>,
|
||||||
pub desc: Vec<String>,
|
pub desc: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
@ -417,24 +430,7 @@ pub struct Task {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
pub title: String,
|
pub title: String,
|
||||||
pub when: Vec<Spec>, // Should not be empty?
|
pub statements: Vec<Statement>,
|
||||||
pub from: Option<NaiveDate>,
|
|
||||||
pub until: Option<NaiveDate>,
|
|
||||||
pub except: Vec<NaiveDate>,
|
|
||||||
pub desc: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct BirthdaySpec {
|
|
||||||
pub date: NaiveDate,
|
|
||||||
pub year_known: bool, // If year is unknown, use NaiveDate of year 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Birthday {
|
|
||||||
pub title: String,
|
|
||||||
pub when: BirthdaySpec,
|
|
||||||
// pub until: Option<NaiveDate>, // TODO Add UNTIL to birthday
|
|
||||||
pub desc: Vec<String>,
|
pub desc: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -442,7 +438,6 @@ pub struct Birthday {
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
Task(Task),
|
Task(Task),
|
||||||
Note(Note),
|
Note(Note),
|
||||||
Birthday(Birthday),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use std::fmt;
|
||||||
use chrono::Datelike;
|
use chrono::Datelike;
|
||||||
|
|
||||||
use super::commands::{
|
use super::commands::{
|
||||||
Birthday, BirthdaySpec, Command, DateSpec, Delta, DeltaStep, Done, DoneDate, Expr, File,
|
BirthdaySpec, Command, DateSpec, Delta, DeltaStep, Done, DoneDate, Expr, File, FormulaSpec,
|
||||||
FormulaSpec, Note, Repeat, Spanned, Spec, Task, Time, Var, Weekday, WeekdaySpec,
|
Note, Repeat, Spanned, Spec, Statement, Task, Time, Var, Weekday, WeekdaySpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<T: fmt::Display> fmt::Display for Spanned<T> {
|
impl<T: fmt::Display> fmt::Display for Spanned<T> {
|
||||||
|
|
@ -191,13 +191,36 @@ impl fmt::Display for FormulaSpec {
|
||||||
|
|
||||||
impl fmt::Display for Spec {
|
impl fmt::Display for Spec {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(f, "DATE ")?;
|
|
||||||
match self {
|
match self {
|
||||||
Spec::Date(spec) => write!(f, "{}", spec)?,
|
Spec::Date(spec) => write!(f, "{}", spec),
|
||||||
Spec::Weekday(spec) => write!(f, "{}", spec)?,
|
Spec::Weekday(spec) => write!(f, "{}", spec),
|
||||||
Spec::Formula(spec) => write!(f, "{}", spec)?,
|
Spec::Formula(spec) => write!(f, "{}", spec),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for BirthdaySpec {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
if self.year_known {
|
||||||
|
write!(f, "{}", self.date)
|
||||||
|
} else {
|
||||||
|
write!(f, "?-{:02}-{:02}", self.date.month(), self.date.day())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Statement {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Statement::Date(spec) => writeln!(f, "DATE {}", spec),
|
||||||
|
Statement::BDate(spec) => writeln!(f, "BDATE {}", spec),
|
||||||
|
Statement::From(Some(date)) => writeln!(f, "FROM {}", date),
|
||||||
|
Statement::From(None) => writeln!(f, "FROM *"),
|
||||||
|
Statement::Until(Some(date)) => writeln!(f, "UNTIL {}", date),
|
||||||
|
Statement::Until(None) => writeln!(f, "UNTIL *"),
|
||||||
|
Statement::Except(date) => writeln!(f, "EXCEPT {}", date),
|
||||||
|
Statement::Move(from, to) => writeln!(f, "MOVE {} TO {}", from, to),
|
||||||
}
|
}
|
||||||
writeln!(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,17 +253,8 @@ impl fmt::Display for Done {
|
||||||
impl fmt::Display for Task {
|
impl fmt::Display for Task {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f, "TASK {}", self.title)?;
|
writeln!(f, "TASK {}", self.title)?;
|
||||||
for spec in &self.when {
|
for statement in &self.statements {
|
||||||
write!(f, "{}", spec)?;
|
write!(f, "{}", statement)?;
|
||||||
}
|
|
||||||
if let Some(date) = self.from {
|
|
||||||
writeln!(f, "FROM {}", date)?;
|
|
||||||
}
|
|
||||||
if let Some(date) = self.until {
|
|
||||||
writeln!(f, "UNTIL {}", date)?;
|
|
||||||
}
|
|
||||||
for date in &self.except {
|
|
||||||
writeln!(f, "EXCEPT {}", date)?;
|
|
||||||
}
|
}
|
||||||
for done in &self.done {
|
for done in &self.done {
|
||||||
write!(f, "{}", done)?;
|
write!(f, "{}", done)?;
|
||||||
|
|
@ -253,37 +267,9 @@ impl fmt::Display for Task {
|
||||||
impl fmt::Display for Note {
|
impl fmt::Display for Note {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
writeln!(f, "NOTE {}", self.title)?;
|
writeln!(f, "NOTE {}", self.title)?;
|
||||||
for spec in &self.when {
|
for statement in &self.statements {
|
||||||
write!(f, "{}", spec)?;
|
write!(f, "{}", statement)?;
|
||||||
}
|
}
|
||||||
if let Some(date) = self.from {
|
|
||||||
writeln!(f, "FROM {}", date)?;
|
|
||||||
}
|
|
||||||
if let Some(date) = self.until {
|
|
||||||
writeln!(f, "UNTIL {}", date)?;
|
|
||||||
}
|
|
||||||
for date in &self.except {
|
|
||||||
writeln!(f, "EXCEPT {}", date)?;
|
|
||||||
}
|
|
||||||
format_desc(f, &self.desc)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for BirthdaySpec {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
if self.year_known {
|
|
||||||
writeln!(f, "BDATE {}", self.date)
|
|
||||||
} else {
|
|
||||||
writeln!(f, "BDATE ?-{:02}-{:02}", self.date.month(), self.date.day())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Birthday {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
writeln!(f, "BIRTHDAY {}", self.title)?;
|
|
||||||
write!(f, "{}", self.when)?;
|
|
||||||
format_desc(f, &self.desc)?;
|
format_desc(f, &self.desc)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +280,6 @@ impl fmt::Display for Command {
|
||||||
match self {
|
match self {
|
||||||
Command::Task(task) => write!(f, "{}", task),
|
Command::Task(task) => write!(f, "{}", task),
|
||||||
Command::Note(note) => write!(f, "{}", note),
|
Command::Note(note) => write!(f, "{}", note),
|
||||||
Command::Birthday(birthday) => write!(f, "{}", birthday),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,12 +101,14 @@ date_weekday_start = { weekday ~ time? }
|
||||||
date_weekday_end = { weekday ~ time? | delta ~ time? | time }
|
date_weekday_end = { weekday ~ time? | delta ~ time? | time }
|
||||||
date_weekday = { date_weekday_start ~ ("--" ~ date_weekday_end)? }
|
date_weekday = { date_weekday_start ~ ("--" ~ date_weekday_end)? }
|
||||||
|
|
||||||
date = !{ "DATE" ~ (date_fixed | date_expr | date_weekday) ~ eol }
|
stmt_date = !{ "DATE" ~ (date_fixed | date_expr | date_weekday) ~ eol }
|
||||||
|
stmt_bdate = !{ "BDATE" ~ bdatum ~ eol }
|
||||||
|
stmt_from = !{ "FROM" ~ (datum | "*") ~ eol }
|
||||||
|
stmt_until = !{ "UNTIL" ~ (datum | "*") ~ eol }
|
||||||
|
stmt_except = !{ "EXCEPT" ~ datum ~ eol }
|
||||||
|
stmt_move = !{ "MOVE" ~ datum ~ "TO" ~ datum ~ eol }
|
||||||
|
|
||||||
bdate = !{ "BDATE" ~ bdatum ~ eol }
|
statements = { (stmt_date | stmt_bdate | stmt_from | stmt_until | stmt_except | stmt_move)* }
|
||||||
from = !{ "FROM" ~ datum ~ eol }
|
|
||||||
until = !{ "UNTIL" ~ datum ~ eol }
|
|
||||||
except = !{ "EXCEPT" ~ datum ~ eol }
|
|
||||||
|
|
||||||
donedate = {
|
donedate = {
|
||||||
datum ~ time ~ "--" ~ datum ~ time
|
datum ~ time ~ "--" ~ datum ~ time
|
||||||
|
|
@ -115,36 +117,27 @@ donedate = {
|
||||||
| datum
|
| datum
|
||||||
}
|
}
|
||||||
done = !{ "DONE" ~ "[" ~ datum ~ "]" ~ donedate? ~ eol }
|
done = !{ "DONE" ~ "[" ~ datum ~ "]" ~ donedate? ~ eol }
|
||||||
|
dones = { done* }
|
||||||
|
|
||||||
desc_line = { "#" ~ (" " ~ rest_any)? ~ eol }
|
desc_line = { "#" ~ (" " ~ rest_any)? ~ eol }
|
||||||
description = { desc_line* }
|
description = { desc_line* }
|
||||||
|
|
||||||
task_options = { (date | from | until | except | done)* }
|
|
||||||
|
|
||||||
task = {
|
task = {
|
||||||
"TASK"
|
"TASK"
|
||||||
~ title
|
~ title
|
||||||
~ task_options
|
~ statements
|
||||||
|
~ dones
|
||||||
~ description
|
~ description
|
||||||
}
|
}
|
||||||
|
|
||||||
note_options = { (date | from | until | except)* }
|
|
||||||
|
|
||||||
note = {
|
note = {
|
||||||
"NOTE"
|
"NOTE"
|
||||||
~ title
|
~ title
|
||||||
~ note_options
|
~ statements
|
||||||
~ description
|
|
||||||
}
|
|
||||||
|
|
||||||
birthday = {
|
|
||||||
"BIRTHDAY"
|
|
||||||
~ title
|
|
||||||
~ bdate
|
|
||||||
~ description
|
~ description
|
||||||
}
|
}
|
||||||
|
|
||||||
empty_line = _{ WHITESPACE* ~ NEWLINE }
|
empty_line = _{ WHITESPACE* ~ NEWLINE }
|
||||||
command = { include | timezone | task | note | birthday }
|
command = { include | timezone | task | note }
|
||||||
|
|
||||||
file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI }
|
file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI }
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ use pest::{Parser, Span};
|
||||||
use crate::files::commands::{Repeat, Spanned};
|
use crate::files::commands::{Repeat, Spanned};
|
||||||
|
|
||||||
use super::commands::{
|
use super::commands::{
|
||||||
Birthday, BirthdaySpec, Command, DateSpec, Delta, DeltaStep, Done, DoneDate, Expr, File,
|
BirthdaySpec, Command, DateSpec, Delta, DeltaStep, Done, DoneDate, Expr, File, FormulaSpec,
|
||||||
FormulaSpec, Note, Spec, Task, Time, Var, Weekday, WeekdaySpec,
|
Note, Spec, Statement, Task, Time, Var, Weekday, WeekdaySpec,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(pest_derive::Parser)]
|
#[derive(pest_derive::Parser)]
|
||||||
|
|
@ -532,33 +532,101 @@ fn parse_date_weekday(p: Pair<'_, Rule>) -> Result<WeekdaySpec> {
|
||||||
Ok(spec)
|
Ok(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_date(p: Pair<'_, Rule>) -> Result<Spec> {
|
fn parse_stmt_date(p: Pair<'_, Rule>) -> Result<Statement> {
|
||||||
assert_eq!(p.as_rule(), Rule::date);
|
assert_eq!(p.as_rule(), Rule::stmt_date);
|
||||||
let p = p.into_inner().next().unwrap();
|
let p = p.into_inner().next().unwrap();
|
||||||
match p.as_rule() {
|
let spec = match p.as_rule() {
|
||||||
Rule::date_fixed => parse_date_fixed(p).map(Spec::Date),
|
Rule::date_fixed => Spec::Date(parse_date_fixed(p)?),
|
||||||
Rule::date_expr => parse_date_expr(p).map(Spec::Formula),
|
Rule::date_expr => Spec::Formula(parse_date_expr(p)?),
|
||||||
Rule::date_weekday => parse_date_weekday(p).map(Spec::Weekday),
|
Rule::date_weekday => Spec::Weekday(parse_date_weekday(p)?),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
};
|
||||||
|
Ok(Statement::Date(spec))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from(p: Pair<'_, Rule>) -> Result<NaiveDate> {
|
fn parse_bdatum(p: Pair<'_, Rule>) -> Result<BirthdaySpec> {
|
||||||
assert_eq!(p.as_rule(), Rule::from);
|
assert_eq!(p.as_rule(), Rule::bdatum);
|
||||||
let datum = parse_datum(p.into_inner().next().unwrap())?;
|
let span = p.as_span();
|
||||||
Ok(datum.value)
|
let p = p.into_inner().collect::<Vec<_>>();
|
||||||
|
assert!(p.len() == 2 || p.len() == 3);
|
||||||
|
|
||||||
|
let (y, m, d, year_known) = if p.len() == 3 {
|
||||||
|
let y = p[0].as_str().parse().unwrap();
|
||||||
|
let m = p[1].as_str().parse().unwrap();
|
||||||
|
let d = p[2].as_str().parse().unwrap();
|
||||||
|
(y, m, d, true)
|
||||||
|
} else {
|
||||||
|
let m = p[0].as_str().parse().unwrap();
|
||||||
|
let d = p[1].as_str().parse().unwrap();
|
||||||
|
(0, m, d, false)
|
||||||
|
};
|
||||||
|
|
||||||
|
let date = match NaiveDate::from_ymd_opt(y, m, d) {
|
||||||
|
Some(date) => Ok(date),
|
||||||
|
None => fail(span, "invalid date"),
|
||||||
|
}?;
|
||||||
|
|
||||||
|
Ok(BirthdaySpec { date, year_known })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_until(p: Pair<'_, Rule>) -> Result<NaiveDate> {
|
fn parse_stmt_bdate(p: Pair<'_, Rule>) -> Result<Statement> {
|
||||||
assert_eq!(p.as_rule(), Rule::until);
|
assert_eq!(p.as_rule(), Rule::stmt_bdate);
|
||||||
let datum = parse_datum(p.into_inner().next().unwrap())?;
|
let spec = parse_bdatum(p.into_inner().next().unwrap())?;
|
||||||
Ok(datum.value)
|
Ok(Statement::BDate(spec))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_except(p: Pair<'_, Rule>) -> Result<NaiveDate> {
|
fn parse_stmt_from(p: Pair<'_, Rule>) -> Result<Statement> {
|
||||||
assert_eq!(p.as_rule(), Rule::except);
|
assert_eq!(p.as_rule(), Rule::stmt_from);
|
||||||
let datum = parse_datum(p.into_inner().next().unwrap())?;
|
let mut p = p.into_inner();
|
||||||
Ok(datum.value)
|
let datum = match p.next() {
|
||||||
|
Some(p) => Some(parse_datum(p)?.value),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
assert_eq!(p.next(), None);
|
||||||
|
Ok(Statement::From(datum))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_stmt_until(p: Pair<'_, Rule>) -> Result<Statement> {
|
||||||
|
assert_eq!(p.as_rule(), Rule::stmt_until);
|
||||||
|
let mut p = p.into_inner();
|
||||||
|
let datum = match p.next() {
|
||||||
|
Some(p) => Some(parse_datum(p)?.value),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
assert_eq!(p.next(), None);
|
||||||
|
Ok(Statement::Until(datum))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_stmt_except(p: Pair<'_, Rule>) -> Result<Statement> {
|
||||||
|
assert_eq!(p.as_rule(), Rule::stmt_except);
|
||||||
|
let datum = parse_datum(p.into_inner().next().unwrap())?.value;
|
||||||
|
Ok(Statement::Except(datum))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_stmt_move(p: Pair<'_, Rule>) -> Result<Statement> {
|
||||||
|
assert_eq!(p.as_rule(), Rule::stmt_move);
|
||||||
|
let mut p = p.into_inner();
|
||||||
|
let from = parse_datum(p.next().unwrap())?.value;
|
||||||
|
let to = parse_datum(p.next().unwrap())?.value;
|
||||||
|
assert_eq!(p.next(), None);
|
||||||
|
Ok(Statement::Move(from, to))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_statements(p: Pair<'_, Rule>) -> Result<Vec<Statement>> {
|
||||||
|
assert_eq!(p.as_rule(), Rule::statements);
|
||||||
|
let mut statements = vec![];
|
||||||
|
for p in p.into_inner() {
|
||||||
|
statements.push(match p.as_rule() {
|
||||||
|
Rule::stmt_date => parse_stmt_date(p)?,
|
||||||
|
Rule::stmt_bdate => parse_stmt_bdate(p)?,
|
||||||
|
Rule::stmt_from => parse_stmt_from(p)?,
|
||||||
|
Rule::stmt_until => parse_stmt_until(p)?,
|
||||||
|
Rule::stmt_except => parse_stmt_except(p)?,
|
||||||
|
Rule::stmt_move => parse_stmt_move(p)?,
|
||||||
|
_ => unreachable!(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Ok(statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_donedate(p: Pair<'_, Rule>) -> Result<DoneDate> {
|
fn parse_donedate(p: Pair<'_, Rule>) -> Result<DoneDate> {
|
||||||
|
|
@ -609,36 +677,13 @@ fn parse_done(p: Pair<'_, Rule>) -> Result<Done> {
|
||||||
Ok(Done { date, done_at })
|
Ok(Done { date, done_at })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
fn parse_dones(p: Pair<'_, Rule>) -> Result<Vec<Done>> {
|
||||||
struct Options {
|
assert_eq!(p.as_rule(), Rule::dones);
|
||||||
when: Vec<Spec>,
|
let mut dones = vec![];
|
||||||
from: Option<NaiveDate>,
|
for p in p.into_inner() {
|
||||||
until: Option<NaiveDate>,
|
dones.push(parse_done(p)?);
|
||||||
except: Vec<NaiveDate>,
|
|
||||||
done: Vec<Done>,
|
|
||||||
}
|
}
|
||||||
|
Ok(dones)
|
||||||
fn parse_options(p: Pair<'_, Rule>) -> Result<Options> {
|
|
||||||
assert!(matches!(
|
|
||||||
p.as_rule(),
|
|
||||||
Rule::task_options | Rule::note_options
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut opts = Options::default();
|
|
||||||
for opt in p.into_inner() {
|
|
||||||
match opt.as_rule() {
|
|
||||||
Rule::date => opts.when.push(parse_date(opt)?),
|
|
||||||
Rule::from if opts.from.is_none() => opts.from = Some(parse_from(opt)?),
|
|
||||||
Rule::from => fail(opt.as_span(), "FROM already defined earlier")?,
|
|
||||||
Rule::until if opts.until.is_none() => opts.until = Some(parse_until(opt)?),
|
|
||||||
Rule::until => fail(opt.as_span(), "UNTIL already defined earlier")?,
|
|
||||||
Rule::except => opts.except.push(parse_except(opt)?),
|
|
||||||
Rule::done => opts.done.push(parse_done(opt)?),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(opts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_desc_line(p: Pair<'_, Rule>) -> Result<String> {
|
fn parse_desc_line(p: Pair<'_, Rule>) -> Result<String> {
|
||||||
|
|
@ -662,18 +707,16 @@ fn parse_task(p: Pair<'_, Rule>) -> Result<Task> {
|
||||||
let mut p = p.into_inner();
|
let mut p = p.into_inner();
|
||||||
|
|
||||||
let title = parse_title(p.next().unwrap());
|
let title = parse_title(p.next().unwrap());
|
||||||
let opts = parse_options(p.next().unwrap())?;
|
let statements = parse_statements(p.next().unwrap())?;
|
||||||
|
let done = parse_dones(p.next().unwrap())?;
|
||||||
let desc = parse_description(p.next().unwrap())?;
|
let desc = parse_description(p.next().unwrap())?;
|
||||||
|
|
||||||
assert_eq!(p.next(), None);
|
assert_eq!(p.next(), None);
|
||||||
|
|
||||||
Ok(Task {
|
Ok(Task {
|
||||||
title,
|
title,
|
||||||
when: opts.when,
|
statements,
|
||||||
from: opts.from,
|
done,
|
||||||
until: opts.until,
|
|
||||||
except: opts.except,
|
|
||||||
done: opts.done,
|
|
||||||
desc,
|
desc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -683,63 +726,18 @@ fn parse_note(p: Pair<'_, Rule>) -> Result<Note> {
|
||||||
let mut p = p.into_inner();
|
let mut p = p.into_inner();
|
||||||
|
|
||||||
let title = parse_title(p.next().unwrap());
|
let title = parse_title(p.next().unwrap());
|
||||||
let opts = parse_options(p.next().unwrap())?;
|
let statements = parse_statements(p.next().unwrap())?;
|
||||||
let desc = parse_description(p.next().unwrap())?;
|
let desc = parse_description(p.next().unwrap())?;
|
||||||
|
|
||||||
assert_eq!(p.next(), None);
|
assert_eq!(p.next(), None);
|
||||||
assert!(opts.done.is_empty());
|
|
||||||
|
|
||||||
Ok(Note {
|
Ok(Note {
|
||||||
title,
|
title,
|
||||||
when: opts.when,
|
statements,
|
||||||
from: opts.from,
|
|
||||||
until: opts.until,
|
|
||||||
except: opts.except,
|
|
||||||
desc,
|
desc,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_bdatum(p: Pair<'_, Rule>) -> Result<BirthdaySpec> {
|
|
||||||
assert_eq!(p.as_rule(), Rule::bdatum);
|
|
||||||
let span = p.as_span();
|
|
||||||
let p = p.into_inner().collect::<Vec<_>>();
|
|
||||||
assert!(p.len() == 2 || p.len() == 3);
|
|
||||||
|
|
||||||
let (y, m, d, year_known) = if p.len() == 3 {
|
|
||||||
let y = p[0].as_str().parse().unwrap();
|
|
||||||
let m = p[1].as_str().parse().unwrap();
|
|
||||||
let d = p[2].as_str().parse().unwrap();
|
|
||||||
(y, m, d, true)
|
|
||||||
} else {
|
|
||||||
let m = p[0].as_str().parse().unwrap();
|
|
||||||
let d = p[1].as_str().parse().unwrap();
|
|
||||||
(0, m, d, false)
|
|
||||||
};
|
|
||||||
|
|
||||||
let date = match NaiveDate::from_ymd_opt(y, m, d) {
|
|
||||||
Some(date) => Ok(date),
|
|
||||||
None => fail(span, "invalid date"),
|
|
||||||
}?;
|
|
||||||
|
|
||||||
Ok(BirthdaySpec { date, year_known })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_bdate(p: Pair<'_, Rule>) -> Result<BirthdaySpec> {
|
|
||||||
assert_eq!(p.as_rule(), Rule::bdate);
|
|
||||||
parse_bdatum(p.into_inner().next().unwrap())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_birthday(p: Pair<'_, Rule>) -> Result<Birthday> {
|
|
||||||
assert_eq!(p.as_rule(), Rule::birthday);
|
|
||||||
let mut p = p.into_inner();
|
|
||||||
|
|
||||||
let title = parse_title(p.next().unwrap());
|
|
||||||
let when = parse_bdate(p.next().unwrap())?;
|
|
||||||
let desc = parse_description(p.next().unwrap())?;
|
|
||||||
|
|
||||||
Ok(Birthday { title, when, desc })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_command(p: Pair<'_, Rule>, file: &mut File) -> Result<()> {
|
fn parse_command(p: Pair<'_, Rule>, file: &mut File) -> Result<()> {
|
||||||
assert_eq!(p.as_rule(), Rule::command);
|
assert_eq!(p.as_rule(), Rule::command);
|
||||||
|
|
||||||
|
|
@ -752,7 +750,6 @@ fn parse_command(p: Pair<'_, Rule>, file: &mut File) -> Result<()> {
|
||||||
},
|
},
|
||||||
Rule::task => file.commands.push(Command::Task(parse_task(p)?)),
|
Rule::task => file.commands.push(Command::Task(parse_task(p)?)),
|
||||||
Rule::note => file.commands.push(Command::Note(parse_note(p)?)),
|
Rule::note => file.commands.push(Command::Note(parse_note(p)?)),
|
||||||
Rule::birthday => file.commands.push(Command::Birthday(parse_birthday(p)?)),
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
14
src/main.rs
14
src/main.rs
|
|
@ -8,10 +8,10 @@ use std::path::PathBuf;
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use crate::eval::DateRange;
|
// use crate::eval::DateRange;
|
||||||
use crate::files::Files;
|
use crate::files::Files;
|
||||||
|
|
||||||
mod eval;
|
// mod eval;
|
||||||
mod files;
|
mod files;
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
|
|
@ -26,11 +26,11 @@ fn main() -> anyhow::Result<()> {
|
||||||
let mut files = Files::load(&opt.file)?;
|
let mut files = Files::load(&opt.file)?;
|
||||||
println!("{}", files.now().format("%F %T %Z"));
|
println!("{}", files.now().format("%F %T %Z"));
|
||||||
|
|
||||||
let range = DateRange::new(
|
// let range = DateRange::new(
|
||||||
NaiveDate::from_ymd(2021, 11, 20),
|
// NaiveDate::from_ymd(2021, 11, 20),
|
||||||
NaiveDate::from_ymd(2021, 11, 26),
|
// NaiveDate::from_ymd(2021, 11, 26),
|
||||||
);
|
// );
|
||||||
println!("{:#?}", files.eval(range));
|
// println!("{:#?}", files.eval(range));
|
||||||
|
|
||||||
files.mark_all_dirty();
|
files.mark_all_dirty();
|
||||||
files.save()?;
|
files.save()?;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue