#![doc = include_str!("../README.md")]
use proc_macro::TokenStream;
use proclet::{op, pm1::StringLiteral, prelude::*, proclet, punctuated, Optional};
#[proc_macro]
pub fn str_block(input: TokenStream) -> TokenStream {
proclet(input, |input| {
let strings = punctuated(StringLiteral::parser(), Optional(op(","))).parse_all(input)?;
let str: String = strings.into_iter().map(|(s, _)| s.into_value()).collect();
let mut lines = str.lines();
let mut lines2 = lines.clone();
let Some(first) = lines.next() else {
return Ok(StringLiteral::new(String::new()));
};
let first = if first.trim().is_empty() {
let _ = lines2.next();
if let Some(second) = lines.next() {
second
} else {
return Ok(StringLiteral::new(String::new()));
}
} else {
first
};
let first_trimmed = first.trim_start();
let mut prefix = &first[..first.len() - first_trimmed.len()];
if !prefix.is_empty() {
for line in lines {
if !line.trim().is_empty() {
let ci = prefix
.chars()
.zip(line.chars())
.take_while(|(p, l)| p == l)
.fold(0, |ci, (p, _)| ci + p.len_utf8());
if ci < prefix.len() {
prefix = &prefix[..ci];
if prefix.is_empty() {
break;
}
}
}
}
}
let mut output = String::from(lines2.next().unwrap().strip_prefix(prefix).unwrap_or(""));
for line in lines2 {
output.push('\n');
output.push_str(line.strip_prefix(prefix).unwrap_or(""));
}
if str.ends_with('\n') {
output.push('\n');
}
Ok(StringLiteral::new(output))
})
}