Skip to main content

tex_engine/tex/nodes/
vertical.rs

1/*! Nodes allowed in vertical lists. */
2use crate::engine::filesystem::SourceRef;
3use crate::engine::EngineTypes;
4use crate::tex::nodes::boxes::{TeXBox, ToOrSpread, VBoxInfo};
5use crate::tex::nodes::{display_do_indent, BoxTarget, Leaders, NodeTrait, NodeType, WhatsitNode};
6use crate::tex::numerics::Skip;
7use crate::tex::numerics::TeXDimen;
8use crate::tex::tokens::token_lists::TokenList;
9
10/// A vertical list node.
11#[derive(Clone, Debug)]
12pub enum VNode<ET: EngineTypes> {
13    /// A penalty node, as produced by `\penalty`.
14    Penalty(i32),
15    /// A mark node, as produced by `\mark`.
16    Mark(usize, TokenList<ET::Token>),
17    /// A whatsit node, as produced by `\special`, `\write`, etc.
18    Whatsit(WhatsitNode<ET>),
19    /// A glue node, as produced by `\vskip`.
20    VSkip(Skip<ET::Dim>),
21    /// A glue node, as produced by `\vfil`.
22    VFil,
23    /// A glue node, as produced by `\vfill`.
24    VFill,
25    /// A glue node, as produced by `\vfilneg`.
26    VFilneg,
27    /// A glue node, as produced by `\vss`.
28    Vss,
29    /// A kern node, as produced by `\kern`.
30    VKern(ET::Dim),
31    /// Leaders, as produced by `\leaders` or `\cleaders` or `\xleaders`.
32    Leaders(Leaders<ET>),
33    /// A box node, as produced by `\hbox`, `\vbox`, `\vtop`, etc.
34    Box(TeXBox<ET>),
35    /// A rule node, as produced by `\hrule`.
36    HRule {
37        /// The *provided* width of the rule.
38        width: Option<ET::Dim>,
39        /// The *provided* height of the rule.
40        height: Option<ET::Dim>,
41        /// The *provided* depth of the rule.
42        depth: Option<ET::Dim>,
43        /// The source reference for the start of the rule.
44        start: SourceRef<ET>,
45        /// The source reference for the end of the rule.
46        end: SourceRef<ET>,
47    },
48    /// An insertion node, as produced by `\insert`.
49    Insert(usize, Box<[VNode<ET>]>),
50    /// A custom node.
51    Custom(ET::CustomNode),
52}
53
54impl<ET: EngineTypes> VNode<ET> {
55    /// Whether this node is discardable.
56    pub fn discardable(&self) -> bool {
57        use VNode::*;
58        matches!(
59            self,
60            Penalty(_) | VSkip(_) | VKern(_) | VFil | VFill | VFilneg | Vss
61        )
62    }
63}
64
65impl<ET: EngineTypes> NodeTrait<ET> for VNode<ET> {
66    fn display_fmt(&self, indent: usize, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67        match self {
68            VNode::Penalty(p) => {
69                display_do_indent(indent, f)?;
70                write!(f, "<penalty:{}>", p)
71            }
72            VNode::Leaders(l) => l.display_fmt(indent, f),
73            VNode::VSkip(s) => write!(f, "<vskip:{}>", s),
74            VNode::VFil => write!(f, "<vfil>"),
75            VNode::VFill => write!(f, "<vfill>"),
76            VNode::VFilneg => write!(f, "<vfilneg>"),
77            VNode::Vss => write!(f, "<vss>"),
78            VNode::VKern(d) => write!(f, "<vkern:{}>", d),
79            VNode::HRule {
80                width,
81                height,
82                depth,
83                ..
84            } => {
85                write!(f, "<hrule")?;
86                if let Some(w) = width {
87                    write!(f, " width={}", w)?;
88                }
89                if let Some(h) = height {
90                    write!(f, " height={}", h)?;
91                }
92                if let Some(d) = depth {
93                    write!(f, " depth={}", d)?;
94                }
95                write!(f, ">")
96            }
97            VNode::Box(b) => b.display_fmt(indent, f),
98            VNode::Mark(i, _) => {
99                display_do_indent(indent, f)?;
100                write!(f, "<mark:{}>", i)
101            }
102            VNode::Insert(n, ch) => {
103                display_do_indent(indent, f)?;
104                write!(f, "<insert {}>", n)?;
105                for c in ch.iter() {
106                    c.display_fmt(indent + 2, f)?;
107                }
108                display_do_indent(indent, f)?;
109                write!(f, "</insert>")
110            }
111            VNode::Whatsit(w) => {
112                display_do_indent(indent, f)?;
113                write!(f, "{:?}", w)
114            }
115            VNode::Custom(n) => n.display_fmt(indent, f),
116        }
117    }
118    fn height(&self) -> ET::Dim {
119        match self {
120            VNode::VKern(d) => *d,
121            VNode::Box(b) => b.height(),
122            VNode::Leaders(l) => l.height(),
123            VNode::HRule { height, .. } => height.unwrap_or(ET::Dim::from_sp(26214)),
124            VNode::Custom(n) => n.height(),
125            VNode::VSkip(s) => s.base,
126            _ => ET::Dim::default(),
127        }
128    }
129    fn width(&self) -> ET::Dim {
130        match self {
131            VNode::Box(b) => b.width(),
132            VNode::HRule { width, .. } => width.unwrap_or_default(),
133            VNode::Custom(n) => n.width(),
134            VNode::Leaders(l) => l.width(),
135            _ => ET::Dim::default(),
136        }
137    }
138    fn depth(&self) -> ET::Dim {
139        match self {
140            VNode::Box(b) => b.depth(),
141            VNode::HRule { depth, .. } => depth.unwrap_or_default(),
142            VNode::Custom(n) => n.depth(),
143            VNode::Leaders(l) => l.depth(),
144            _ => ET::Dim::default(),
145        }
146    }
147    fn nodetype(&self) -> NodeType {
148        match self {
149            VNode::Penalty(_) => NodeType::Penalty,
150            VNode::HRule { .. } => NodeType::Rule,
151            VNode::Leaders(_) => NodeType::Glue,
152            VNode::Box(b) => b.nodetype(),
153            VNode::VKern(_) => NodeType::Kern,
154            VNode::Insert(..) => NodeType::Insertion,
155            VNode::Mark(_, _) => NodeType::Mark,
156            VNode::Whatsit(_) => NodeType::WhatsIt,
157            VNode::Custom(n) => n.nodetype(),
158            VNode::VSkip(_) | VNode::VFil | VNode::VFill | VNode::VFilneg | VNode::Vss => {
159                NodeType::Glue
160            }
161        }
162    }
163    fn opaque(&self) -> bool {
164        match self {
165            VNode::Mark(_, _) => true,
166            VNode::Custom(n) => n.opaque(),
167            _ => false,
168        }
169    }
170    fn sourceref(&self) -> Option<(&SourceRef<ET>, &SourceRef<ET>)> {
171        match self {
172            VNode::HRule { start, end, .. } => Some((start, end)),
173            VNode::Box(b) => b.sourceref(),
174            _ => None,
175        }
176    }
177}
178
179/// The kinds of vertical lists that can occur. TODO: rethink this
180#[derive(Clone, Debug)]
181pub enum VerticalNodeListType<ET: EngineTypes> {
182    /// A vertical box
183    Box(VBoxInfo<ET>, SourceRef<ET>, BoxTarget<ET>),
184    /// `\insert`
185    Insert(usize),
186    /// `\vcenter`
187    VCenter(SourceRef<ET>, ToOrSpread<ET::Dim>),
188    /// `\vadjust`
189    VAdjust,
190    /// A column in a `\valign`. The source ref indicates the start of the column.
191    VAlignColumn(SourceRef<ET>),
192    /// A cell in a `\valign`. The source ref indicates the start of the cell.
193    /// The `u8` indicates the number of *additional* rows spanned by this cell
194    /// (so by default 0)
195    VAlignCell(SourceRef<ET>, u8),
196    /// An `\halign` list
197    HAlign,
198    /// A page to be output
199    Page,
200}