orgize/src/elements/dyn_block.rs

65 lines
1.8 KiB
Rust

use memchr::{memchr, memchr_iter};
// return (name, parameters, offset, limit, end)
#[inline]
pub fn parse(text: &str) -> Option<(&str, Option<&str>, usize, usize, usize)> {
debug_assert!(text.starts_with("#+"));
if text.len() <= "#+BEGIN: ".len() || !text[2..9].eq_ignore_ascii_case("BEGIN: ") {
return None;
}
let bytes = text.as_bytes();
let mut lines = memchr_iter(b'\n', bytes);
let (name, para, off) = lines
.next()
.map(|i| {
memchr(b' ', &bytes["#+BEGIN: ".len()..i])
.map(|x| {
(
&text["#+BEGIN: ".len().."#+BEGIN: ".len() + x],
Some(text["#+BEGIN: ".len() + x..i].trim()),
i + 1,
)
})
.unwrap_or((&text["#+BEGIN: ".len()..i], None, i + 1))
})
.filter(|(name, _, _)| name.as_bytes().iter().all(|&c| c.is_ascii_alphabetic()))?;
let mut pos = off;
for i in lines {
if text[pos..i].trim().eq_ignore_ascii_case("#+END:") {
return Some((name, para, off, pos, i + 1));
}
pos = i + 1;
}
if text[pos..].trim().eq_ignore_ascii_case("#+END:") {
Some((name, para, off, pos, text.len()))
} else {
None
}
}
#[cfg(test)]
mod tests {
#[test]
fn parse() {
use super::parse;
// TODO: testing
assert_eq!(
parse("#+BEGIN: clocktable :scope file\nCONTENTS\n#+END:\n"),
Some((
"clocktable",
Some(":scope file"),
"#+BEGIN: clocktable :scope file\n".len(),
"#+BEGIN: clocktable :scope file\nCONTENTS\n".len(),
"#+BEGIN: clocktable :scope file\nCONTENTS\n#+END:\n".len(),
))
);
}
}