use crate::support::Extrude;
use crate::types::MdBlock;
pub struct MdBlockIter<'a> {
lang_filter: Option<&'a str>,
extrude: Option<Extrude>,
lines: std::str::Lines<'a>,
extruded_content: Vec<&'a str>,
}
impl<'a> MdBlockIter<'a> {
pub fn new(content: &'a str, lang_filter: Option<&'a str>, extrude: Option<Extrude>) -> Self {
MdBlockIter {
lines: content.lines(),
lang_filter,
extrude,
extruded_content: Vec::new(),
}
}
fn next_block(&mut self) -> Option<MdBlock> {
let mut in_block: Option<&str> = None;
let mut captured_content: Option<Vec<&str>> = None;
let extrude_content = matches!(self.extrude, Some(Extrude::Content));
for line in self.lines.by_ref() {
if line.starts_with("```") {
if in_block.is_none() {
let lang = line.trim_start_matches("```").trim();
in_block = Some(lang);
captured_content = match self.lang_filter {
Some(filter) => {
if filter == lang {
Some(Vec::new())
} else {
if extrude_content {
self.extruded_content.push(line);
self.extruded_content.push("\n");
}
None
}
}
None => Some(Vec::new()),
};
}
else {
if let Some(content) = captured_content {
let content = content.join("");
return Some(MdBlock {
lang: Some(in_block.unwrap_or_default().to_string()),
content,
});
} else if extrude_content {
self.extruded_content.push(line);
self.extruded_content.push("\n");
}
in_block = None;
captured_content = None;
}
continue;
}
if let Some(content) = &mut captured_content {
content.push(line);
content.push("\n");
}
else if extrude_content {
self.extruded_content.push(line);
self.extruded_content.push("\n");
}
}
None
}
}
impl MdBlockIter<'_> {
pub fn collect_blocks_and_extruded_content(mut self) -> (Vec<MdBlock>, String) {
let mut blocks: Vec<MdBlock> = Vec::new();
for block in self.by_ref() {
blocks.push(block);
}
let extruded_content = self.extruded_content.join("");
(blocks, extruded_content)
}
}
impl Iterator for MdBlockIter<'_> {
type Item = MdBlock;
fn next(&mut self) -> Option<Self::Item> {
self.next_block()
}
}
#[path = "../../_tests/tests_support_md_block_iter.rs"]
#[cfg(test)]
mod tests;