From 2f64e1e6afa104884140496b79538cc032a3133f Mon Sep 17 00:00:00 2001 From: PoiScript Date: Mon, 20 Nov 2023 01:46:13 +0800 Subject: [PATCH] feat: add todo_type method in Headline --- README.md | 4 ++-- src/ast/generate.js | 1 - src/ast/generated.rs | 3 --- src/ast/headline.rs | 50 ++++++++++++++++++++++++++++++++++++++++++ src/ast/mod.rs | 1 + src/syntax/headline.rs | 39 ++++++++++++-------------------- src/syntax/mod.rs | 3 ++- 7 files changed, 69 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 3745c99..e526c78 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ assert_eq!( HEADLINE@0..18 HEADLINE_STARS@0..1 "*" WHITESPACE@1..2 " " - HEADLINE_KEYWORD@2..6 "DONE" + HEADLINE_KEYWORD_DONE@2..6 "DONE" WHITESPACE@6..7 " " HEADLINE_TITLE@7..13 TEXT@7..13 "Title " @@ -46,7 +46,7 @@ let config = ParseConfig { }; let org = config.parse("* TASK Title 1"); let hdl = org.first_node::().unwrap(); -assert_eq!(hdl.keyword().unwrap().text(), "TASK"); +assert_eq!(hdl.todo_keyword().unwrap().text(), "TASK"); ``` ## Render to html diff --git a/src/ast/generate.js b/src/ast/generate.js index bdd4fbc..d9ac885 100644 --- a/src/ast/generate.js +++ b/src/ast/generate.js @@ -29,7 +29,6 @@ const nodes = [ ["planning", "Planning"], ], children: [["headlines", "Headline"]], - token: [["keyword", "HEADLINE_KEYWORD"]], post_blank: true, }, { diff --git a/src/ast/generated.rs b/src/ast/generated.rs index f2f1246..52e17cc 100644 --- a/src/ast/generated.rs +++ b/src/ast/generated.rs @@ -154,9 +154,6 @@ impl Headline { pub fn end(&self) -> u32 { self.syntax.text_range().end().into() } - pub fn keyword(&self) -> Option { - support::token(&self.syntax, HEADLINE_KEYWORD) - } pub fn section(&self) -> Option
{ support::child(&self.syntax) } diff --git a/src/ast/headline.rs b/src/ast/headline.rs index 296f699..63bf75a 100644 --- a/src/ast/headline.rs +++ b/src/ast/headline.rs @@ -1,3 +1,5 @@ +use rowan::NodeOrToken; + use crate::{ syntax::{SyntaxKind, SyntaxToken}, SyntaxElement, @@ -5,6 +7,12 @@ use crate::{ use super::{filter_token, Headline, Timestamp}; +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum TodoType { + Todo, + Done, +} + impl Headline { /// Return level of this headline /// @@ -27,6 +35,48 @@ impl Headline { }) } + /// ```rust + /// use orgize::{Org, ast::Headline}; + /// + /// let hdl = Org::parse("* TODO a").first_node::().unwrap(); + /// assert_eq!(hdl.todo_keyword().unwrap().text(), "TODO"); + /// ``` + pub fn todo_keyword(&self) -> Option { + self.syntax + .children_with_tokens() + .find_map(|elem| match elem { + NodeOrToken::Token(tk) + if tk.kind() == SyntaxKind::HEADLINE_KEYWORD_TODO + || tk.kind() == SyntaxKind::HEADLINE_KEYWORD_DONE => + { + Some(tk) + } + _ => None, + }) + } + + /// ```rust + /// use orgize::{Org, ast::{Headline, TodoType}}; + /// + /// let hdl = Org::parse("* TODO a").first_node::().unwrap(); + /// assert_eq!(hdl.todo_type().unwrap(), TodoType::Todo); + /// let hdl = Org::parse("*** DONE a").first_node::().unwrap(); + /// assert_eq!(hdl.todo_type().unwrap(), TodoType::Done); + /// ``` + pub fn todo_type(&self) -> Option { + self.syntax + .children_with_tokens() + .find_map(|elem| match elem { + NodeOrToken::Token(tk) if tk.kind() == SyntaxKind::HEADLINE_KEYWORD_TODO => { + Some(TodoType::Todo) + } + NodeOrToken::Token(tk) if tk.kind() == SyntaxKind::HEADLINE_KEYWORD_DONE => { + Some(TodoType::Done) + } + _ => None, + }) + } + /// ```rust /// use orgize::{Org, ast::Headline}; /// diff --git a/src/ast/mod.rs b/src/ast/mod.rs index d9a5430..366916c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -15,6 +15,7 @@ mod table; mod timestamp; pub use generated::*; +pub use headline::*; pub use rowan::ast::support::*; pub use timestamp::*; diff --git a/src/syntax/headline.rs b/src/syntax/headline.rs index 01330fc..0d1915f 100644 --- a/src/syntax/headline.rs +++ b/src/syntax/headline.rs @@ -2,7 +2,7 @@ use memchr::memrchr_iter; use nom::{ bytes::complete::take_while1, character::complete::{anychar, space0}, - combinator::{map, opt, verify}, + combinator::{map, opt}, sequence::tuple, AsBytes, IResult, InputLength, InputTake, Slice, }; @@ -203,17 +203,15 @@ fn headline_tags_node(input: Input) -> IResult { } fn headline_keyword_token(input: Input) -> IResult { - let (input, word) = verify( - take_while1(|c: char| !c.is_ascii_whitespace()), - |input: &Input| { - let Input { c, s } = input; - c.todo_keywords.0.iter().any(|k| k == s) || c.todo_keywords.1.iter().any(|k| k == s) - }, - )(input)?; - + let (input, word) = take_while1(|c: char| !c.is_ascii_whitespace())(input)?; let (input, ws) = space0(input)?; - - Ok((input, (word.token(HEADLINE_KEYWORD), ws))) + if input.c.todo_keywords.0.iter().any(|k| k == word.s) { + Ok((input, (word.token(HEADLINE_KEYWORD_TODO), ws))) + } else if input.c.todo_keywords.1.iter().any(|k| k == word.s) { + Ok((input, (word.token(HEADLINE_KEYWORD_DONE), ws))) + } else { + Err(nom::Err::Error(())) + } } fn headline_priority_node(input: Input) -> IResult { @@ -238,10 +236,8 @@ fn parse() { let to_headline = to_ast::(headline_node); - let hdl = to_headline("* foo"); - insta::assert_debug_snapshot!( - hdl.syntax, + to_headline("* foo").syntax, @r###" HEADLINE@0..5 HEADLINE_STARS@0..1 "*" @@ -251,9 +247,8 @@ fn parse() { "### ); - let hdl = to_headline("* foo\n\n** bar"); insta::assert_debug_snapshot!( - hdl.syntax, + to_headline("* foo\n\n** bar").syntax, @r###" HEADLINE@0..13 HEADLINE_STARS@0..1 "*" @@ -272,16 +267,13 @@ fn parse() { "### ); - let hdl = to_headline("* TODO foo\nbar\n** baz\n"); - assert_eq!(hdl.level(), 1); - assert_eq!(hdl.keyword().unwrap().text(), "TODO"); insta::assert_debug_snapshot!( - hdl.syntax, + to_headline("* TODO foo\nbar\n** baz\n").syntax, @r###" HEADLINE@0..22 HEADLINE_STARS@0..1 "*" WHITESPACE@1..2 " " - HEADLINE_KEYWORD@2..6 "TODO" + HEADLINE_KEYWORD_TODO@2..6 "TODO" WHITESPACE@6..7 " " HEADLINE_TITLE@7..10 TEXT@7..10 "foo" @@ -298,11 +290,8 @@ fn parse() { "### ); - let hdl = to_headline("** [#A] foo\n* baz"); - assert_eq!(hdl.level(), 2); - assert_eq!(hdl.priority().unwrap().text(), "A"); insta::assert_debug_snapshot!( - hdl.syntax, + to_headline("** [#A] foo\n* baz").syntax, @r###" HEADLINE@0..12 HEADLINE_STARS@0..2 "**" diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs index c2c6084..f53e1b0 100644 --- a/src/syntax/mod.rs +++ b/src/syntax/mod.rs @@ -117,7 +117,8 @@ pub enum SyntaxKind { HEADLINE, HEADLINE_STARS, HEADLINE_TITLE, - HEADLINE_KEYWORD, + HEADLINE_KEYWORD_TODO, + HEADLINE_KEYWORD_DONE, HEADLINE_PRIORITY, HEADLINE_TAGS, PROPERTY_DRAWER,