use crate::Composite;
#[derive(Debug, Default, PartialEq, Eq)]
struct Arg {
compounds_idx: Vec<usize>, }
#[allow(dead_code)] impl Arg {
fn add(
&mut self,
idx: usize,
) {
self.compounds_idx.push(idx);
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct InlineTemplate<'a> {
composite: Composite<'a>,
args: [Arg; 10],
}
impl<'a> InlineTemplate<'a> {
pub fn from(md: &'a str) -> InlineTemplate<'a> {
let mut composite = Composite::from_inline(md);
let mut compounds = Vec::new();
let mut args: [Arg; 10] = Default::default();
for compound in composite.compounds {
let mut after_dollar = false;
let mut start = 0;
for (idx, char) in compound.as_str().char_indices() {
if after_dollar {
if char.is_ascii_digit() {
let num: u8 = (char as u8) - b'0';
if start + 1 < idx {
compounds.push(compound.sub(start, idx - 1));
}
start = idx + 1;
args[usize::from(num)].compounds_idx.push(compounds.len());
compounds.push(compound.sub(idx - 1, start)); }
after_dollar = false;
} else if char == '$' {
after_dollar = true;
}
}
let tail = compound.tail(start);
if !tail.is_empty() {
compounds.push(tail);
}
}
composite.compounds = compounds;
InlineTemplate { composite, args }
}
pub fn raw_composite(&self) -> Composite<'a> {
self.composite.clone()
}
pub fn apply(
&self,
composite: &mut Composite<'a>,
arg_idx: usize,
value: &'a str,
) {
if arg_idx > 9 {
return;
}
for compound_idx in &self.args[arg_idx].compounds_idx {
composite.compounds[*compound_idx].set_str(value.as_ref());
}
}
}
#[macro_export]
macro_rules! mad_inline {
( $md: literal $(, $value: expr )* $(,)? ) => {{
use minimad::once_cell::sync::Lazy;
static TEMPLATE: Lazy<minimad::InlineTemplate<'static>> = Lazy::new(|| {
minimad::InlineTemplate::from($md)
});
#[allow(unused_mut)]
#[allow(unused_variables)]
let mut arg_idx = 0;
#[allow(unused_mut)]
let mut composite = TEMPLATE.raw_composite();
$(
TEMPLATE.apply(&mut composite, arg_idx, $value);
#[allow(unused_assignments)] { arg_idx += 1; }
)*
composite
}};
}
#[cfg(test)]
mod tests {
use crate::{
self as minimad, template::inline_template::*,
*,
};
#[test]
fn simple_template_parsing() {
let mut args = <[Arg; 10]>::default();
args[0].add(3);
args[1].add(1);
assert_eq!(
InlineTemplate::from("test $1 and $0"),
InlineTemplate {
composite: Composite::from(vec![
Compound::raw_str("test "),
Compound::raw_str("$1"),
Compound::raw_str(" and "),
Compound::raw_str("$0"),
]),
args,
},
);
let mut args = <[Arg; 10]>::default();
args[0].add(1);
args[2].add(0);
args[2].add(2);
assert_eq!(
InlineTemplate::from("$2$0$2 "), InlineTemplate {
composite: Composite::from(vec![
Compound::raw_str("$2"),
Compound::raw_str("$0"),
Compound::raw_str("$2"),
Compound::raw_str(" "),
]),
args,
},
);
}
#[test]
fn simple_composition() {
let template = InlineTemplate::from("using $1 and **$0**");
let mut composite = template.raw_composite();
template.apply(&mut composite, 0, "First");
assert_eq!(
composite,
Composite::from(vec![
Compound::raw_str("using "),
Compound::raw_str("$1"),
Compound::raw_str(" and "),
Compound::raw_str("First").bold(),
]),
);
}
#[test]
fn macro_empty_composition() {
let composite = mad_inline!("some `code`");
assert_eq!(
composite,
Composite::from(vec![
Compound::raw_str("some "),
Compound::raw_str("code").code(),
]),
);
}
#[test]
fn macro_complex_composition() {
let composite = mad_inline!("**$1:** `$0`", "π*r²", "area");
assert_eq!(
composite,
Composite::from(vec![
Compound::raw_str("area").bold(),
Compound::raw_str(":").bold(),
Compound::raw_str(" "),
Compound::raw_str("π*r²").code(),
]),
);
}
}