use crate::diag::bail;
use crate::foundations::{cast, elem, func, Content, NativeElement, SymbolElem};
use crate::layout::{Length, Rel};
use crate::math::Mathy;
#[elem(Mathy)]
pub struct AccentElem {
#[required]
pub base: Content,
#[required]
pub accent: Accent,
#[resolve]
#[default(Rel::one())]
pub size: Rel<Length>,
}
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct Accent(pub char);
impl Accent {
pub fn new(c: char) -> Self {
Self(Self::combine(c).unwrap_or(c))
}
}
macro_rules! accents {
($($primary:literal $(| $alt:literal)* => $name:ident),* $(,)?) => {
impl Accent {
pub fn combine(c: char) -> Option<char> {
Some(match c {
$($primary $(| $alt)* => $primary,)*
_ => return None,
})
}
}
$(
#[func]
pub fn $name(
base: Content,
#[named]
size: Option<Rel<Length>>,
) -> Content {
let mut accent = AccentElem::new(base, Accent::new($primary));
if let Some(size) = size {
accent = accent.with_size(size);
}
accent.pack()
}
)+
};
}
accents! {
'\u{0300}' | '`' => grave,
'\u{0301}' | '´' => acute,
'\u{0302}' | '^' | 'ˆ' => hat,
'\u{0303}' | '~' | '∼' | '˜' => tilde,
'\u{0304}' | '¯' => macron,
'\u{0305}' | '-' | '‾' | '−' => dash,
'\u{0306}' | '˘' => breve,
'\u{0307}' | '.' | '˙' | '⋅' => dot,
'\u{0308}' | '¨' => dot_double,
'\u{20db}' => dot_triple,
'\u{20dc}' => dot_quad,
'\u{030a}' | '∘' | '○' => circle,
'\u{030b}' | '˝' => acute_double,
'\u{030c}' | 'ˇ' => caron,
'\u{20d6}' | '←' => arrow_l,
'\u{20d7}' | '→' | '⟶' => arrow,
'\u{20e1}' | '↔' | '⟷' => arrow_l_r,
'\u{20d0}' | '↼' => harpoon_lt,
'\u{20d1}' | '⇀' => harpoon,
}
cast! {
Accent,
self => self.0.into_value(),
v: char => Self::new(v),
v: Content => match v.to_packed::<SymbolElem>() {
Some(elem) => Self::new(elem.text),
None => bail!("expected a symbol"),
},
}