2023-10-29 17:29:16 -04:00
|
|
|
use super::macros::intermediate;
|
2023-10-29 22:31:29 -04:00
|
|
|
|
2023-10-29 17:29:16 -04:00
|
|
|
use crate::error::CustomError;
|
2023-10-27 17:08:58 -04:00
|
|
|
|
2023-10-29 15:36:15 -04:00
|
|
|
#[derive(Debug, Clone)]
|
2023-10-29 09:37:27 -04:00
|
|
|
pub(crate) struct ISrcBlock {
|
|
|
|
pub(crate) lines: Vec<String>,
|
2023-12-21 12:07:36 -05:00
|
|
|
pub(crate) language: Option<String>,
|
2023-10-29 09:37:27 -04:00
|
|
|
}
|
2023-10-27 17:08:58 -04:00
|
|
|
|
2023-12-19 17:09:11 -05:00
|
|
|
intermediate!(
|
|
|
|
ISrcBlock,
|
|
|
|
&'orig organic::types::SrcBlock<'parse>,
|
|
|
|
original,
|
|
|
|
_registry,
|
|
|
|
{
|
2023-12-21 12:27:34 -05:00
|
|
|
let source_code = original.get_value();
|
|
|
|
let prefix_content_pairs: Vec<_> = source_code
|
2023-12-19 17:09:11 -05:00
|
|
|
.split_inclusive('\n')
|
2023-12-21 12:27:34 -05:00
|
|
|
.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
|
|
|
|
})
|
2023-12-19 17:09:11 -05:00
|
|
|
.collect();
|
2023-12-21 12:07:36 -05:00
|
|
|
let language = original.language.map(str::to_owned);
|
|
|
|
Ok(ISrcBlock { lines, language })
|
2023-12-19 17:09:11 -05:00
|
|
|
}
|
|
|
|
);
|
2023-12-21 12:27:34 -05:00
|
|
|
|
|
|
|
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."),
|
|
|
|
}
|
|
|
|
}
|