feat(headline): support custom keywords
This commit is contained in:
parent
88e1f8d62d
commit
c7de340479
|
@ -2,6 +2,9 @@
|
|||
|
||||
use memchr::memchr2;
|
||||
|
||||
const HEADLINE_DEFAULT_KEYWORDS: &'static [&'static str] =
|
||||
&["TODO", "DONE", "NEXT", "WAITING", "LATER", "CANCELLED"];
|
||||
|
||||
#[cfg_attr(test, derive(PartialEq))]
|
||||
#[derive(Debug)]
|
||||
pub struct Headline<'a> {
|
||||
|
@ -35,10 +38,10 @@ impl<'a> Headline<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_keyword(src: &'a str) -> Option<(&'a str, usize)> {
|
||||
fn parse_keyword(src: &'a str, keywords: &'a [&'a str]) -> Option<(&'a str, usize)> {
|
||||
let pos = memchr2(b' ', b'\n', src.as_bytes()).unwrap_or_else(|| src.len());
|
||||
let word = &src[0..pos];
|
||||
if word.as_bytes().iter().all(|&c| c.is_ascii_uppercase()) && word != "COMMENT" {
|
||||
if keywords.contains(&word) {
|
||||
Some((word, pos))
|
||||
} else {
|
||||
None
|
||||
|
@ -74,6 +77,13 @@ impl<'a> Headline<'a> {
|
|||
/// assert_eq!(hdl.keyword, Some("DONE"));
|
||||
/// ```
|
||||
pub fn parse(src: &'a str) -> (Headline<'a>, usize, usize) {
|
||||
Self::parse_with_keywords(src, HEADLINE_DEFAULT_KEYWORDS)
|
||||
}
|
||||
|
||||
pub fn parse_with_keywords(
|
||||
src: &'a str,
|
||||
keywords: &'a [&'a str],
|
||||
) -> (Headline<'a>, usize, usize) {
|
||||
let level = memchr2(b'\n', b' ', src.as_bytes()).unwrap_or_else(|| src.len());
|
||||
|
||||
debug_assert!(level > 0);
|
||||
|
@ -85,7 +95,7 @@ impl<'a> Headline<'a> {
|
|||
|
||||
let mut title_start = skip_space!(src, level);
|
||||
|
||||
let keyword = Headline::parse_keyword(&src[title_start..eol]).map(|(k, l)| {
|
||||
let keyword = Headline::parse_keyword(&src[title_start..eol], keywords).map(|(k, l)| {
|
||||
title_start += l;
|
||||
k
|
||||
});
|
||||
|
@ -153,6 +163,10 @@ impl<'a> Headline<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Headline;
|
||||
|
||||
#[test]
|
||||
fn parse() {
|
||||
assert_eq!(
|
||||
|
@ -235,6 +249,27 @@ fn parse() {
|
|||
keyword: None,
|
||||
},
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
Headline::parse_with_keywords("**** TODO [#A] COMMENT Title :tag:a2%:", &[]).0,
|
||||
Headline {
|
||||
level: 4,
|
||||
priority: None,
|
||||
keyword: None,
|
||||
title: "TODO [#A] COMMENT Title",
|
||||
tags: Some(":tag:a2%:"),
|
||||
},
|
||||
);
|
||||
assert_eq!(
|
||||
Headline::parse_with_keywords("**** TASK [#A] COMMENT Title :tag:a2%:", &["TASK"]).0,
|
||||
Headline {
|
||||
level: 4,
|
||||
priority: Some('A'),
|
||||
keyword: Some("TASK"),
|
||||
title: "COMMENT Title",
|
||||
tags: Some(":tag:a2%:"),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -269,3 +304,4 @@ fn find_level() {
|
|||
10
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,6 +200,7 @@ pub struct Parser<'a> {
|
|||
ele_buf: Option<(Element<'a>, usize)>,
|
||||
obj_buf: Option<(Object<'a>, usize)>,
|
||||
has_more_item: bool,
|
||||
keywords: Option<&'a [&'a str]>,
|
||||
}
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
|
@ -212,6 +213,7 @@ impl<'a> Parser<'a> {
|
|||
ele_buf: None,
|
||||
obj_buf: None,
|
||||
has_more_item: false,
|
||||
keywords: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +227,10 @@ impl<'a> Parser<'a> {
|
|||
self.stack.len()
|
||||
}
|
||||
|
||||
pub fn set_keywords(&mut self, keywords: &'a [&'a str]) {
|
||||
self.keywords = Some(keywords)
|
||||
}
|
||||
|
||||
fn next_sec_or_hdl(&mut self) -> Event<'a> {
|
||||
let end = Headline::find_level(&self.text[self.off..], std::usize::MAX);
|
||||
debug_assert!(end <= self.text[self.off..].len());
|
||||
|
@ -239,7 +245,11 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
fn next_hdl(&mut self) -> Event<'a> {
|
||||
let (hdl, off, end) = Headline::parse(&self.text[self.off..]);
|
||||
let (hdl, off, end) = if let Some(keywords) = self.keywords {
|
||||
Headline::parse_with_keywords(&self.text[self.off..], keywords)
|
||||
} else {
|
||||
Headline::parse(&self.text[self.off..])
|
||||
};
|
||||
debug_assert!(end <= self.text[self.off..].len());
|
||||
self.stack.push(Container::Headline {
|
||||
beg: self.off + off,
|
||||
|
|
Loading…
Reference in a new issue