use crate::Engine;
use crate::cmd::Cmd;
use crate::eqtb::{Loc, MU_GLUE_OFFSET, NUM_FAMILIES, Val};
use crate::glue::Glue;
use crate::maincontrol::Mode;
use crate::nodes::NodeRef;
impl Engine {
pub fn print_glue(&mut self, d: i32, order: u8, s: Option<&str>) {
self.printer.print_scaled(d);
if order > 4 {
self.printer.print_str("foul");
} else if order > 0 {
self.printer.print_str("fi");
for _ in 1..order {
self.printer.print_char('l' as u32);
}
} else if let Some(s) = s {
self.printer.print_str(s);
}
}
pub fn print_spec(&mut self, g: &Glue, s: Option<&str>) {
self.printer.print_scaled(g.width);
if let Some(s) = s {
self.printer.print_str(s);
}
if g.stretch != 0 {
self.printer.print_str(" plus ");
self.print_glue(g.stretch, g.stretch_order, s);
}
if g.shrink != 0 {
self.printer.print_str(" minus ");
self.print_glue(g.shrink, g.shrink_order, s);
}
}
pub fn show_eqtb(&mut self, loc: Loc) {
match loc {
Loc::Cs(cs) => {
self.sprint_cs(cs);
self.printer.print_char('=' as u32);
let m = self.eqtb.meaning(cs).clone();
if m.cmd.is_call() && m.mac.as_ref().is_some_and(|mac| mac.protected) {
self.print_esc_str("protected");
if m.cmd == Cmd::Call {
self.printer.print_char(' ' as u32);
}
}
self.print_cmd_chr(m.cmd, m.chr);
if m.cmd >= Cmd::Call
&& let Some(mac) = m.mac
{
self.printer.print_char(':' as u32);
let t = mac.tokens.clone();
self.show_token_list(&t, 0, t.len(), 32);
}
}
Loc::IntPar(i) => {
self.print_cmd_chr(Cmd::AssignInt, i);
self.printer.print_char('=' as u32);
self.printer.print_int(self.eqtb.int(i).into());
}
Loc::Count(n) => {
self.print_esc_str("count");
self.printer.print_int(n.into());
self.printer.print_char('=' as u32);
self.printer
.print_int(self.eqtb.count[n as usize].val.into());
}
Loc::Attr(n) => {
self.print_esc_str("attribute");
self.printer.print_int(n.into());
self.printer.print_char('=' as u32);
self.printer
.print_int(self.eqtb.attr[n as usize].val.into());
}
Loc::DimenPar(i) => {
self.print_cmd_chr(Cmd::AssignDimen, i);
self.printer.print_char('=' as u32);
self.printer.print_scaled(self.eqtb.dimen(i));
self.printer.print_str("pt");
}
Loc::Dimen(n) => {
self.print_esc_str("dimen");
self.printer.print_int(n.into());
self.printer.print_char('=' as u32);
self.printer.print_scaled(self.eqtb.dimen[n as usize].val);
self.printer.print_str("pt");
}
Loc::GluePar(i) => {
let mu = i >= MU_GLUE_OFFSET;
if mu {
self.print_cmd_chr(Cmd::AssignMuGlue, i - MU_GLUE_OFFSET);
} else {
self.print_cmd_chr(Cmd::AssignGlue, i);
}
self.printer.print_char('=' as u32);
let g = self.eqtb.glue(i);
self.print_spec(&g, Some(if mu { "mu" } else { "pt" }));
}
Loc::Skip(n) | Loc::MuSkip(n) => {
let mu = matches!(loc, Loc::MuSkip(_));
self.print_esc_str(if mu { "muskip" } else { "skip" });
self.printer.print_int(n.into());
self.printer.print_char('=' as u32);
let g = if mu {
self.eqtb.muskip[n as usize].val
} else {
self.eqtb.skip[n as usize].val
};
self.print_spec(&g, Some(if mu { "mu" } else { "pt" }));
}
Loc::ToksPar(_) | Loc::Toks(_) => {
if let Loc::Toks(n) = loc {
self.print_esc_str("toks");
self.printer.print_int(n.into());
} else if let Loc::ToksPar(i) = loc {
self.print_cmd_chr(Cmd::AssignToks, i);
}
self.printer.print_char('=' as u32);
if let Val::Toks(t) = self.eqtb.get(loc) {
self.show_token_list(&t, 0, t.len(), 32);
}
}
Loc::Box(n) => {
self.print_esc_str("box");
self.printer.print_int(n.into());
self.printer.print_char('=' as u32);
let b = self.eqtb.boxes[n as usize].val;
if b.is_null() {
self.printer.print_str("void");
} else {
self.depth_threshold = 0;
self.breadth_max = 1;
self.show_box1(b);
}
}
Loc::CurFont => {
self.printer.print_str("current font");
self.printer.print_char('=' as u32);
let cs = self.font_id_cs(self.eqtb.cur_font.val);
let name = self.hash.name(cs).to_vec();
self.print_esc_bytes(&name);
}
Loc::MathFont(i) => {
let size = i / NUM_FAMILIES as u32;
let fam = i % NUM_FAMILIES as u32;
self.print_cmd_chr(Cmd::DefFamily, size);
self.printer.print_int(fam.into());
self.printer.print_char('=' as u32);
let cs = self.font_id_cs(self.eqtb.math_font[i as usize].val);
let name = self.hash.name(cs).to_vec();
self.print_esc_bytes(&name);
}
Loc::ParShape => {
self.print_esc_str("parshape");
self.printer.print_char('=' as u32);
let n = self.eqtb.par_shape.val.as_ref().map_or(0, |s| s.len() / 2);
self.printer.print_int(n as i64);
}
Loc::EtexShape(i) => {
self.print_cmd_chr(Cmd::SetEtexShape, i);
self.printer.print_char('=' as u32);
let n = self.eqtb.etex_shape[i as usize]
.val
.as_ref()
.map_or(0, |s| s.len());
self.printer.print_int(n as i64);
}
Loc::Cat { table, ch } => {
self.print_esc_str("catcode");
self.printer.print_int(ch.into());
self.printer.print_char('=' as u32);
self.printer
.print_int(self.eqtb.catcode_in(table, ch).into());
}
Loc::Code(kind, ch) => {
use crate::eqtb::CodeKind as K;
let name = match kind {
K::Lc => "lccode",
K::Uc => "uccode",
K::Sf => "sfcode",
K::Math => "mathcode",
K::Del => "delcode",
};
self.print_esc_str(name);
self.printer.print_int(ch.into());
self.printer.print_char('=' as u32);
self.printer.print_int(self.eqtb.code_table(kind).get(ch));
}
Loc::MathParam(i) => {
self.print_cmd_chr(Cmd::SetMathParam, i / 8);
self.printer.print_int((i % 8).into());
self.printer.print_char('=' as u32);
if let Val::Int(v) = self.eqtb.get(loc) {
self.printer.print_scaled(v as i32);
self.printer.print_str("pt");
}
}
Loc::LocalCount(i) => {
self.print_esc_str(if i == 0 {
"nolocalwhatsits"
} else {
"nolocaldirs"
});
self.printer.print_char('=' as u32);
self.printer
.print_int(self.eqtb.local_count[i as usize].val.into());
}
Loc::DirPar(i) => {
const NAMES: [&str; 6] = [
"pagedir", "bodydir", "pardir", "textdir", "mathdir", "linedir",
];
self.print_esc_str(NAMES.get(i as usize).copied().unwrap_or("textdir"));
self.printer.print_char(' ' as u32);
let d = self.eqtb.dir_par[i as usize].val;
self.printer
.print_str(crate::showbox::DIR_NAMES[d.rem_euclid(4) as usize]);
}
Loc::LocalBox(i) => {
self.print_esc_str(if i == 0 {
"localleftbox"
} else {
"localrightbox"
});
self.printer.print_char('=' as u32);
let b = self.eqtb.local_box[i as usize].val;
if b.is_null() {
self.printer.print_str("void");
} else {
self.depth_threshold = 0;
self.breadth_max = 1;
self.show_box1(b);
}
}
}
}
pub fn show_box(&mut self, p: NodeRef) {
self.show_box_param_limits();
self.show_node_list(p);
self.printer.print_ln();
}
pub fn show_box1(&mut self, p: NodeRef) {
self.show_node_list(p);
}
pub fn show_save_groups(&mut self) {
use crate::save::{GroupCode, SaveEntry};
let (v_level, v_group, v_boundary) = (
self.save.cur_level,
self.save.cur_group,
self.save.cur_boundary,
);
let saved = |e: &Engine, b: usize, k: usize| -> i64 {
match b.checked_sub(k).and_then(|i| e.save.stack.get(i)) {
Some(SaveEntry::Value(v)) => *v,
_ => 0,
}
};
let mode_of = |e: &Engine, p: usize| e.nest.get(p).map(|l| l.mode);
let mut p = self.nest.len() - 1;
let mut a: i32 = 1;
self.printer.print_nl("");
self.printer.print_ln();
self.save.cur_level = self.save.cur_level.saturating_sub(1);
loop {
self.printer.print_nl("### ");
self.print_group(true);
let group = self.save.cur_group;
if group == GroupCode::BottomLevel {
break;
}
let b = self.save.cur_boundary;
let mut m;
loop {
m = mode_of(self, p).unwrap_or(Mode::Vertical);
if p > 0 {
p -= 1;
} else {
m = Mode::Vertical;
}
if m != Mode::Horizontal {
break;
}
}
self.printer.print_str(" (");
enum Tail {
Box(&'static str, bool),
Brace,
Close,
}
let tail = match group {
GroupCode::Simple => {
p += 1;
Tail::Brace
}
GroupCode::Hbox | GroupCode::AdjustedHbox => Tail::Box("hbox", true),
GroupCode::Vbox => Tail::Box("vbox", true),
GroupCode::Vtop => Tail::Box("vtop", true),
GroupCode::Align => {
if a == 0 {
a = 1;
Tail::Box(
if m == Mode::InternalVertical {
"halign"
} else {
"valign"
},
false,
)
} else {
if a == 1 {
self.printer.print_str("align entry");
} else {
self.print_esc_str("cr");
}
if p as i32 >= a {
p = (p as i32 - a) as usize;
}
a = 0;
Tail::Close
}
}
GroupCode::NoAlign => {
p += 1;
a = -1;
self.print_esc_str("noalign");
Tail::Brace
}
GroupCode::Output => {
self.print_esc_str("output");
Tail::Close
}
GroupCode::Math => Tail::Brace,
GroupCode::Disc | GroupCode::MathChoice => {
self.print_esc_str(if group == GroupCode::Disc {
"discretionary"
} else {
"mathchoice"
});
let n = saved(self, b, 1);
for i in 1..=3 {
if i <= n {
self.printer.print_str("{}");
}
}
Tail::Brace
}
GroupCode::Insert => {
let n = match self.save.stack.get(b) {
Some(SaveEntry::Boundary { line, .. }) => i64::from(*line),
_ => 0,
};
if n == 255 {
self.print_esc_str("vadjust");
} else {
self.print_esc_str("insert");
self.printer.print_int(n);
}
Tail::Brace
}
GroupCode::Vcenter => Tail::Box("vcenter", false),
GroupCode::SemiSimple => {
p += 1;
self.print_esc_str("begingroup");
Tail::Close
}
GroupCode::MathShift => {
if m == Mode::DisplayMath {
self.printer.print_char('$' as u32);
} else if mode_of(self, p) == Some(Mode::DisplayMath) {
self.print_cmd_chr(crate::cmd::Cmd::EqNo, saved(self, b, 1) as u32);
self.printer.print_str(")");
self.save_groups_next();
continue;
}
self.printer.print_char('$' as u32);
Tail::Close
}
GroupCode::MathLeft => {
let left = self
.nest
.get(p + 1)
.map(|l| l.delim_ptr)
.is_some_and(|d| !d.is_null() && self.nodes.subtype(d) == 1);
self.print_esc_str(if left { "left" } else { "middle" });
Tail::Close
}
_ => Tail::Close,
};
if let Tail::Box(s, context) = tail {
if context {
let i = saved(self, b, 2);
match crate::build::ctx_from_i64(i) {
crate::maincontrol::BoxContext::Shift(0) => {}
crate::maincontrol::BoxContext::Shift(d) => {
let vertical = mode_of(self, p).is_some_and(|m| {
matches!(m, Mode::Vertical | Mode::InternalVertical)
});
let cmd = if vertical {
crate::cmd::Cmd::Hmove
} else {
crate::cmd::Cmd::Vmove
};
self.print_cmd_chr(cmd, u32::from(d < 0));
self.printer.print_scaled(d.abs());
self.printer.print_str("pt");
}
crate::maincontrol::BoxContext::SetBox(n) => {
self.print_esc_str("setbox");
self.printer.print_int(i64::from(n));
self.printer.print_char('=' as u32);
}
crate::maincontrol::BoxContext::GlobalSetBox(n) => {
self.print_esc_str("global");
self.print_esc_str("setbox");
self.printer.print_int(i64::from(n));
self.printer.print_char('=' as u32);
}
crate::maincontrol::BoxContext::Shipout => self.print_esc_str("shipout"),
crate::maincontrol::BoxContext::Leaders(sub) => {
self.print_cmd_chr(crate::cmd::Cmd::LeaderShip, u32::from(sub))
}
}
}
self.print_esc_str(s);
let (code, d) = (saved(self, b, 3), saved(self, b, 2));
if d != 0 {
self.printer.print_char(' ' as u32);
self.printer
.print_str(if code == 0 { "to" } else { "spread" });
self.printer.print_scaled(d as i32);
self.printer.print_str("pt");
}
self.printer.print_char('{' as u32);
} else if let Tail::Brace = tail {
self.printer.print_char('{' as u32);
}
self.printer.print_char(')' as u32);
self.save_groups_next();
}
self.save.cur_level = v_level;
self.save.cur_group = v_group;
self.save.cur_boundary = v_boundary;
}
fn save_groups_next(&mut self) {
self.save.cur_level = self.save.cur_level.saturating_sub(1);
if let Some(crate::save::SaveEntry::Boundary {
group, boundary, ..
}) = self.save.stack.get(self.save.cur_boundary)
{
self.save.cur_group = *group;
self.save.cur_boundary = *boundary;
} else {
self.save.cur_group = crate::save::GroupCode::BottomLevel;
}
}
}