Registry / RepositoryTypeScriptRustPython
Rollpie
ReadmeFiles
Versions
Info
Download
0.2.3555.5 KB2026-10-160.2.2572.8 KB2026-10-150.2.1580.5 KB2026-10-150.2.0579.9 KB2026-09-150.1.1576.6 KB2026-09-12
Version
0.2.2
Copyright
Rollpie, Irohabook
Publisher
math
Published
2026-10-15
Size
572.8 KB
Downloads
28
Checksum
ce26f898ba26eb49c71ebc68597f62f268b83e41bb265b1b5a01688966054588
Dependencies
None

node.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
//! Types of the syntax tree


/// The class of a symbol. It decides the space before and after it, and whether it is italic
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Class {
    /// A character typeset in italic as a variable
    Variable,
    /// An ordinary character typeset upright (such as a digit)
    Ordinary,
    /// Binary operator
    Binary,
    /// Relation symbol
    Relation,
    /// Opening delimiter
    Open,
    /// Closing delimiter
    Close,
    /// Separator
    Punctuation,
    /// Function name
    Function,
    /// Large operator
    Large,
    /// Space that has only a width. The value is in em
    Space(f64),
}


/// Style of a character
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Style {
    /// Decided by the class (only variables are italic)
    Auto,
    /// Upright
    Roman,
    /// Italic
    Italic,
    /// Bold
    Bold,
    /// Bold italic
    BoldItalic,
    /// Blackboard bold
    Blackboard,
    /// Script letters
    Script,
    /// Fraktur
    Fraktur,
    /// Sans serif
    SansSerif,
    /// Monospace
    Monospace,
}


/// Whether scripts are placed directly above and below the base
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Limits {
    /// Above and below only in display. The default for large operators
    Auto,
    /// Always above and below
    Always,
    /// Always at the side
    Never,
}


/// Level of typesetting
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Level {
    Display,
    Text,
    Script,
    ScriptScript,
}


/// How a column of a matrix is aligned
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Align {
    Left,
    Center,
    Right,
}


/// How space is put between the columns and rows of a matrix
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Spacing {
    /// matrix, array, and the like. All columns are separated by the same space
    Matrix,
    /// align, aligned, and gather from amsmath. A right-aligned column and a left-aligned
    /// column are packed together as one pair, and space is put between the pairs
    Align,
    /// alignat from amsmath. The pairs are packed together too, with no space between them
    Alignat,
}


/// Syntax tree of a formula
#[derive(Debug, Clone, PartialEq)]
pub enum Node {
    /// A single symbol. The text may have more than one character (sin, log, and so on)
    Symbol {
        text: String,
        class: Class,
    },
    /// The content of \text{...}. It keeps spaces as they are and is typeset upright
    Text(String),
    /// A sequence of items placed side by side
    Row(Vec<Node>),
    /// A fraction. If bar is false, no rule is drawn (\binom)
    Fraction {
        numerator: Box<Node>,
        denominator: Box<Node>,
        bar: bool,
    },
    /// A radical. The index is the 3 in \sqrt[3]{x}
    Root {
        index: Option<Box<Node>>,
        body: Box<Node>,
    },
    /// Superscript and subscript
    Scripts {
        base: Box<Node>,
        superscript: Option<Box<Node>>,
        subscript: Option<Box<Node>>,
        limits: Limits,
    },
    /// Stretchy delimiters that fit the height of the content. A side that is not needed is an
    /// empty string
    Fenced {
        left: &'static str,
        right: &'static str,
        body: Box<Node>,
    },
    /// A matrix. rows[row][column] is a cell, and lines holds the numbers of the rows that have
    /// a horizontal rule drawn just before them
    Matrix {
        rows: Vec<Vec<Node>>,
        left: &'static str,
        right: &'static str,
        align: Vec<Align>,
        lines: Vec<usize>,
        spacing: Spacing,
    },
    /// Content with its style changed
    Styled {
        style: Style,
        body: Box<Node>,
    },
    /// An operator name (\operatorname). The content is typeset upright, and the space before
    /// and after it is the same as for function names such as \sin
    Operator {
        body: Box<Node>,
    },
    /// An accent attached to the content. If above is false, it goes below
    Accent {
        mark: &'static str,
        body: Box<Node>,
        above: bool,
    },
    /// Content with its typesetting level switched
    Sized {
        level: Level,
        body: Box<Node>,
    },
    /// A delimiter with a given size. The height is in em
    Delimiter {
        text: &'static str,
        height: f64,
        class: Class,
    },
    /// A symbol that stretches to the width of what is placed above and below it
    Extend {
        mark: &'static str,
        above: Option<Box<Node>>,
        below: Option<Box<Node>>,
    },
    /// A rule across the whole content. It goes above if above is true, and below if false
    Line {
        body: Box<Node>,
        above: bool,
    },
    /// Something that takes up space but draws nothing
    ///
    /// The width and height fields tell which dimensions of the content are kept.
    /// `\phantom` keeps both, `\hphantom` keeps only the width, and `\vphantom` only the height
    Phantom {
        body: Box<Node>,
        width: bool,
        height: bool,
    },
}


/// Creates an empty Row
pub fn empty() -> Node {
    Node::Row(Vec::new())
}


/// Whether the node is a Row with no items
pub fn is_empty(node: &Node) -> bool {
    matches!(node, Node::Row(items) if items.is_empty())
}


/// The class used to decide the space before and after a node. Every group is treated as
/// Ordinary
pub fn class_of(node: &Node) -> Class {
    match node {
        Node::Symbol {class, ..} => *class,
        Node::Scripts {base, ..} => class_of(base),
        Node::Styled {body, ..} => class_of(body),
        Node::Operator {..} => Class::Function,
        Node::Sized {body, ..} => class_of(body),
        Node::Delimiter {class, ..} => *class,
        Node::Extend {..} => Class::Relation,
        _ => Class::Ordinary,
    }
}


/// Name of the CSS class
pub fn class_name(class: Class) -> &'static str {
    match class {
        Class::Variable => "variable",
        Class::Ordinary => "ordinary",
        Class::Binary => "binary",
        Class::Relation => "relation",
        Class::Open => "open",
        Class::Close => "close",
        Class::Punctuation => "punctuation",
        Class::Function => "function",
        Class::Large => "large",
        Class::Space(_) => "space",
    }
}