From d7c843ed8643dbac11aa643ff1530942035f978e Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 19 Nov 2021 00:48:12 +0100 Subject: [PATCH] Change description format Descriptions must now be prefixed by a '#' symbol instead of indented. --- src/commands.rs | 6 +++--- src/parse.rs | 29 ++++++++++++++--------------- src/parse/todayfile.pest | 16 +++++++--------- 3 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index 66d56e7..42c581b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -213,7 +213,7 @@ pub struct Task { pub until: Option, pub except: Vec, pub done: Vec, - pub desc: Option, + pub desc: Vec, } #[derive(Debug)] @@ -223,7 +223,7 @@ pub struct Note { pub from: Option, pub until: Option, pub except: Vec, - pub desc: Option, + pub desc: Vec, } #[derive(Debug)] @@ -236,7 +236,7 @@ pub struct BirthdaySpec { pub struct Birthday { pub title: String, pub when: BirthdaySpec, - pub desc: Option, + pub desc: Vec, } #[derive(Debug)] diff --git a/src/parse.rs b/src/parse.rs index 6cc1bdc..bffae10 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -24,7 +24,9 @@ fn fail, T>(span: Span, message: S) -> Result { fn parse_title(p: Pair) -> Result { assert_eq!(p.as_rule(), Rule::title); - Ok(p.into_inner().next().unwrap().as_str().to_string()) + let p = p.into_inner().next().unwrap(); + assert_eq!(p.as_rule(), Rule::rest_some); + Ok(p.as_str().to_string()) } fn parse_datum(p: Pair) -> Result { @@ -94,23 +96,20 @@ fn parse_options(p: Pair) -> Result { Ok(opts) } -fn parse_indented_line(p: Pair) -> Result { - assert_eq!(p.as_rule(), Rule::indented_line); - Ok(p.as_str().to_string()) +fn parse_desc_line(p: Pair) -> Result { + assert_eq!(p.as_rule(), Rule::desc_line); + Ok(match p.into_inner().next() { + None => "".to_string(), + Some(p) => { + assert_eq!(p.as_rule(), Rule::rest_any); + p.as_str().to_string() + } + }) } -fn parse_description(p: Pair) -> Result> { +fn parse_description(p: Pair) -> Result> { assert_eq!(p.as_rule(), Rule::description); - - let lines = p - .into_inner() - .map(parse_indented_line) - .collect::>>()?; - - // TODO Strip whitespace prefix - - let desc = lines.join("\n").trim_end().to_string(); - Ok(if desc.is_empty() { None } else { Some(desc) }) + p.into_inner().map(parse_desc_line).collect() } fn parse_task(p: Pair) -> Result { diff --git a/src/parse/todayfile.pest b/src/parse/todayfile.pest index a19b7e4..265f0ad 100644 --- a/src/parse/todayfile.pest +++ b/src/parse/todayfile.pest @@ -1,8 +1,9 @@ eol = _{ NEWLINE | EOI } WHITESPACE = _{ !eol ~ WHITE_SPACE } -rest = { (!eol ~ ANY)+ } +rest_some = { (!eol ~ ANY)+ } +rest_any = { (!eol ~ ANY)* } -title = { WHITESPACE ~ rest ~ eol } +title = { WHITESPACE ~ rest_some ~ eol } year = @{ ASCII_DIGIT{4} } month = @{ ASCII_DIGIT{2} } @@ -72,12 +73,8 @@ except = !{ "EXCEPT" ~ datum ~ eol } donedate = { "(" ~ datum ~ time ~ ")" } done = !{ "DONE" ~ datum? ~ donedate? ~ eol } -// I need to use `NEWLINE` for the empty line here. Otherwise, the parser gets -// into an endless loop at the `EOI` since `indented*` can appear at the end of -// the file and would just repeatedly match the empty string. -indented_line = @{ NEWLINE | WHITESPACE ~ rest ~ eol } - -description = { indented_line* } +desc_line = { "#" ~ (" " ~ rest_any)? ~ eol } +description = { desc_line* } task_options = { (date | from | until | except | done)* } @@ -104,6 +101,7 @@ birthday = { ~ description } +empty_line = _{ WHITESPACE* ~ NEWLINE } command = { task | note | birthday } -file = ${ SOI ~ NEWLINE* ~ command* ~ EOI } +file = ${ SOI ~ (empty_line* ~ command)* ~ empty_line* ~ WHITESPACE* ~ EOI }