use crate::commands::methods::{END_TEMPLATE, END_TEMPLATE_ROW};
use crate::commands::primitives::PRIMITIVES;
use crate::engine::mouth::Mouth;
use crate::engine::state::State;
use crate::engine::{EngineAux, EngineTypes};
use crate::prelude::{CommandCode, Token};
use crate::tex::nodes::boxes::BoxType;
use crate::tex::numerics::Skip;
use crate::tex::tokens::control_sequences::CSHandler;
#[derive(Debug)]
pub struct AlignColumn<T: Token, D: crate::tex::numerics::TeXDimen> {
pub left: Box<[T]>,
pub right: Box<[T]>,
pub inbraces: u8,
pub tabskip: Skip<D>,
}
impl<T: Token, D: crate::tex::numerics::TeXDimen> AlignColumn<T, D> {
pub fn new(mut left: Vec<T>, mut right: Vec<T>, tabskip: Skip<D>, inbraces: u8) -> Self {
left.reverse();
right.reverse();
Self {
left: left.into(),
inbraces,
right: right.into(),
tabskip,
}
}
}
pub struct AlignData<T: Token, D: crate::tex::numerics::TeXDimen> {
pub token: T,
pub ingroups: u8,
pub currindex: usize,
pub repeat_index: Option<usize>,
pub columns: Box<[AlignColumn<T, D>]>,
pub omit: bool,
pub span: bool,
pub inner_mode: BoxType,
pub outer_mode: BoxType,
}
impl<T: Token, D: crate::tex::numerics::TeXDimen> AlignData<T, D> {
pub fn groupval(&self) -> u8 {
if self.omit {
0
} else {
self.columns[self.currindex].inbraces
}
}
pub fn check_token(&mut self, t: &T) -> Option<bool> {
match t.command_code() {
CommandCode::BeginGroup => {
self.ingroups += 1;
Some(true)
}
CommandCode::EndGroup => {
if self.ingroups == 0 {
Some(false)
} else {
self.ingroups -= 1;
Some(true)
}
}
_ => None,
}
}
pub fn dummy() -> Self {
Self {
token: T::space(),
ingroups: 125,
currindex: 0,
repeat_index: None,
columns: Box::new([AlignColumn::new(Vec::new(), Vec::new(), Skip::default(), 0)]),
omit: false,
span: false,
inner_mode: BoxType::Horizontal,
outer_mode: BoxType::Vertical,
}
}
pub fn on_alignment_tab<ET: EngineTypes<Token = T, Dim = D>>(
&self,
mouth: &mut ET::Mouth,
aux: &mut EngineAux<ET>,
) -> T {
let end_align =
<ET::Token as Token>::from_cs(aux.memory.cs_interner_mut().cs_from_str(END_TEMPLATE));
let ls = &*self.columns[self.currindex].right;
if self.omit || ls.is_empty() {
end_align
} else {
mouth.requeue(end_align);
let next = ls.last().unwrap().clone();
mouth.push_slice_rev(&ls[..ls.len() - 1]);
next
}
}
pub fn on_cr<ET: EngineTypes<Token = T, Dim = D>>(
&self,
mouth: &mut ET::Mouth,
aux: &mut EngineAux<ET>,
state: &ET::State,
) -> T {
let everycr = state.get_primitive_tokens(PRIMITIVES.everycr);
mouth.push_exp(everycr);
let end = <ET::Token as Token>::from_cs(
aux.memory.cs_interner_mut().cs_from_str(END_TEMPLATE_ROW),
);
let ls = &*self.columns[self.currindex].right;
if self.omit || ls.is_empty() {
end
} else {
mouth.requeue(end);
let next = ls.last().unwrap().clone();
mouth.push_slice_rev(&ls[..ls.len() - 1]);
next
}
}
}