orgize/src/elements/drawer.rs
2019-06-27 02:57:23 +08:00

69 lines
1.8 KiB
Rust

use memchr::memchr_iter;
#[cfg_attr(test, derive(PartialEq))]
#[derive(Debug)]
pub struct Drawer<'a> {
pub name: &'a str,
}
impl<'a> Drawer<'a> {
#[inline]
// return (drawer, contents-begin, contents-end , end)
pub(crate) fn parse(text: &'a str) -> Option<(Drawer<'a>, usize, usize, usize)> {
debug_assert!(text.starts_with(':'));
let mut lines = memchr_iter(b'\n', text.as_bytes());
let (name, off) = lines
.next()
.map(|i| (text[1..i].trim_end(), i + 1))
.filter(|(name, _)| {
name.ends_with(':')
&& name[0..name.len() - 1]
.as_bytes()
.iter()
.all(|&c| c.is_ascii_alphabetic() || c == b'-' || c == b'_')
})?;
let mut pos = off;
for i in lines {
if text[pos..i].trim().eq_ignore_ascii_case(":END:") {
return Some((
Drawer {
name: &name[0..name.len() - 1],
},
off,
pos,
i + 1,
));
}
pos = i + 1;
}
if text[pos..].trim().eq_ignore_ascii_case(":END:") {
Some((
Drawer {
name: &name[0..name.len() - 1],
},
off,
pos,
text.len(),
))
} else {
None
}
}
}
#[test]
fn parse() {
assert_eq!(
Drawer::parse(":PROPERTIES:\n :CUSTOM_ID: id\n :END:"),
Some((
Drawer { name: "PROPERTIES" },
":PROPERTIES:\n".len(),
":PROPERTIES:\n :CUSTOM_ID: id\n".len(),
":PROPERTIES:\n :CUSTOM_ID: id\n :END:".len()
))
)
}