use super::macros::intermediate; use crate::error::CustomError; use organic::types::StandardProperties; #[derive(Debug, Clone)] pub(crate) struct ISrcBlock { pub(crate) lines: Vec, pub(crate) language: Option, pub(crate) post_blank: organic::types::PostBlank, } intermediate!( ISrcBlock, &'orig organic::types::SrcBlock<'parse>, original, _intermediate_context, { let source_code = original.get_value(); let prefix_content_pairs: Vec<_> = source_code .split_inclusive('\n') .map(|line| { line.find(|c: char| !c.is_ascii_whitespace() && c != '\n') .map(|content_start| line.split_at(content_start)) .map(|(leading_whitespace, content)| { ( leading_whitespace .chars() .map(ascii_whitespace_value) .sum::(), content, ) }) .unwrap_or((0, line)) }) .collect(); let common_whitespace_prefix = prefix_content_pairs .iter() .filter_map(|(leading_whitespace, _content)| { if *leading_whitespace > 0 { Some(*leading_whitespace) } else { None } }) .min() .unwrap_or(0); let lines: Vec<_> = prefix_content_pairs .into_iter() .map(|(leading_whitespace, content)| { let mut line = String::with_capacity(common_whitespace_prefix + content.len()); if leading_whitespace > common_whitespace_prefix { // Empty lines can have a leading_whitespace less than common_whitespace_prefix. for _ in 0..(leading_whitespace - common_whitespace_prefix) { line.push(' '); } } line.push_str(content); line }) .collect(); let language = original.language.map(str::to_owned); Ok(ISrcBlock { lines, language, post_blank: original.get_post_blank(), }) } ); fn ascii_whitespace_value(c: char) -> usize { match c { ' ' => 1, '\t' => 8, '\r' | '\n' => 0, c if c as u32 == 12 => 0, // form feed _ => unreachable!("Only ascii whitespace can reach this code."), } }