feat: add todo_type method in Headline

This commit is contained in:
PoiScript 2023-11-20 01:46:13 +08:00
parent c432d335f1
commit 2f64e1e6af
No known key found for this signature in database
GPG key ID: 22C2B1249D99985E
7 changed files with 69 additions and 32 deletions

View file

@ -29,7 +29,6 @@ const nodes = [
["planning", "Planning"],
],
children: [["headlines", "Headline"]],
token: [["keyword", "HEADLINE_KEYWORD"]],
post_blank: true,
},
{

View file

@ -154,9 +154,6 @@ impl Headline {
pub fn end(&self) -> u32 {
self.syntax.text_range().end().into()
}
pub fn keyword(&self) -> Option<SyntaxToken> {
support::token(&self.syntax, HEADLINE_KEYWORD)
}
pub fn section(&self) -> Option<Section> {
support::child(&self.syntax)
}

View file

@ -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::<Headline>().unwrap();
/// assert_eq!(hdl.todo_keyword().unwrap().text(), "TODO");
/// ```
pub fn todo_keyword(&self) -> Option<SyntaxToken> {
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::<Headline>().unwrap();
/// assert_eq!(hdl.todo_type().unwrap(), TodoType::Todo);
/// let hdl = Org::parse("*** DONE a").first_node::<Headline>().unwrap();
/// assert_eq!(hdl.todo_type().unwrap(), TodoType::Done);
/// ```
pub fn todo_type(&self) -> Option<TodoType> {
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};
///

View file

@ -15,6 +15,7 @@ mod table;
mod timestamp;
pub use generated::*;
pub use headline::*;
pub use rowan::ast::support::*;
pub use timestamp::*;

View file

@ -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<Input, GreenElement, ()> {
}
fn headline_keyword_token(input: Input) -> IResult<Input, (GreenElement, Input), ()> {
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<Input, (GreenElement, Input), ()> {
@ -238,10 +236,8 @@ fn parse() {
let to_headline = to_ast::<Headline>(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 "**"

View file

@ -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,