natter/src/intermediate/src_block.rs

79 lines
2.6 KiB
Rust
Raw Normal View History

use super::macros::intermediate;
use crate::error::CustomError;
2023-12-21 14:56:58 -05:00
use organic::types::StandardProperties;
2023-10-27 17:08:58 -04:00
2023-10-29 15:36:15 -04:00
#[derive(Debug, Clone)]
pub(crate) struct ISrcBlock {
pub(crate) lines: Vec<String>,
pub(crate) language: Option<String>,
2023-12-21 14:56:58 -05:00
pub(crate) post_blank: organic::types::PostBlank,
}
2023-10-27 17:08:58 -04:00
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::<usize>(),
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);
2023-12-21 14:56:58 -05:00
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."),
}
}