use crate::support::Extrude;
use crate::support::md::InBlockState;
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 block_state = InBlockState::Out;
let mut current_lang: Option<String> = None;
let mut captured_content: Option<Vec<&'a str>> = None;
let extrude_content = matches!(self.extrude, Some(Extrude::Content));
for line in self.lines.by_ref() {
let previous_state = block_state;
block_state = block_state.compute_new(line);
if previous_state.is_out() && !block_state.is_out() {
let lang = match block_state {
InBlockState::In4 => line.strip_prefix("````").unwrap_or(line).trim(),
InBlockState::In3 => line.strip_prefix("```").unwrap_or(line).trim(),
_ => line.trim(), };
current_lang = Some(lang.to_string());
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()),
};
continue;
}
if !previous_state.is_out() && block_state.is_out() {
if let Some(content) = captured_content.take() {
let joined = content.join("");
let block = MdBlock {
lang: current_lang.clone(),
content: joined,
};
return Some(block);
} else if extrude_content {
self.extruded_content.push(line);
self.extruded_content.push("\n");
}
current_lang = None;
continue;
}
if !block_state.is_out() {
if let Some(ref mut cap) = captured_content {
cap.push(line);
cap.push("\n");
} else if extrude_content {
self.extruded_content.push(line);
self.extruded_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;