Registry / RepositoryTypeScriptRustPython
Rollpie
ReadmeFiles
Versions
Info
Download
0.4.01085.8 KB2026-10-160.3.21087.6 KB2026-10-160.3.11087.5 KB2026-10-160.3.0117.8 KB2026-10-160.2.1106.1 KB2026-10-150.2.0105.5 KB2026-10-15
Version
0.2.0
Copyright
Rollpie, Irohabook
Publisher
math
Published
2026-10-15
Size
105.5 KB
Downloads
24
Checksum
f438a48f6f2fc61d892f930eb4fb56fb5a8e302e733a8c3a6283d0ff7350cd08
Dependencies
rust/[email protected]
rust/[email protected]

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
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
//! 文書の木
//!
//! 読み取りが作り、組み上げが読む。位置も寸法もここには入らない。
//! 番号だけは [`crate::number`] があとから書き込む。

/// 文書 1 つぶん
#[derive(Debug, Clone, PartialEq)]
pub struct Document {
    /// `\documentclass` に書いた名前
    pub class: String,
    /// `\documentclass` に書いた選び方
    pub option: Vec<String>,
    pub title: Vec<Node>,
    pub author: Vec<Node>,
    pub date: Vec<Node>,
    pub body: Vec<Node>,
}


/// 字の装い
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Face {
    Roman,
    Italic,
    Bold,
    BoldItalic,
    Mono,
    Sans,
}


/// 揃え方
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Align {
    Left,
    Center,
    Right,
    /// 両端を揃える
    Justify,
}


/// 箇条書きの種類
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ListKind {
    /// 印を並べる
    Bullet,
    /// 番号を振る
    Number,
    /// 見出しと説明を並べる
    Description,
}


/// 浮かせるものの種類
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FloatKind {
    Figure,
    Table,
}


/// 長さの書き方
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Length {
    /// 絶対の長さ(pt)
    Absolute(f64),
    /// 本文の幅に対する割合
    Relative(f64),
    /// 本文の字の大きさに対する倍率
    Em(f64),
}


/// 数式 1 行
#[derive(Debug, Clone, PartialEq)]
pub struct MathRow {
    /// 揃え位置で切った式。1 つだけなら揃えない
    pub part: Vec<String>,
    /// この行を引くための名前
    pub label: Option<String>,
    /// この行に番号を振るか
    pub numbered: bool,
    /// 振られた番号。[`crate::number`] が書き込む
    pub number: String,
}


/// 箇条書きの 1 項目
#[derive(Debug, Clone, PartialEq)]
pub struct Item {
    /// `\item[…]` に書いた印。なければ種類ごとの既定の印になる
    pub mark: Option<Vec<Node>>,
    pub body: Vec<Node>,
}


/// 表の桁
#[derive(Debug, Clone, PartialEq)]
pub struct Column {
    pub align: Align,
    /// `p{…}` で決め打ちにした幅
    pub width: Option<Length>,
}


/// 表の枡
#[derive(Debug, Clone, PartialEq)]
pub struct Cell {
    pub body: Vec<Node>,
    /// またがる桁の数
    pub span: usize,
    /// またがるときの揃え方
    pub align: Option<Align>,
}


/// 表の行
#[derive(Debug, Clone, PartialEq)]
pub struct Row {
    pub cell: Vec<Cell>,
    /// この行の上に横罫を引くか
    pub line_above: bool,
}


/// 表
#[derive(Debug, Clone, PartialEq)]
pub struct Table {
    pub column: Vec<Column>,
    /// 桁のあいだの縦罫。長さは桁の数 + 1
    pub rule: Vec<bool>,
    pub row: Vec<Row>,
    /// いちばん下に横罫を引くか
    pub line_below: bool,
}


/// 参考文献の 1 項目
#[derive(Debug, Clone, PartialEq)]
pub struct Reference {
    pub key: String,
    /// `\bibitem[…]` に書いた印。なければ番号
    pub mark: Option<String>,
    pub body: Vec<Node>,
    /// 振られた番号。[`crate::number`] が書き込む
    pub number: String,
}


/// 文書を組み立てる要素
#[derive(Debug, Clone, PartialEq)]
pub enum Node {
    /// 地の文
    Text(String),
    /// 語の切れ目
    Space,
    /// 切れない空き
    HardSpace,
    /// 決まった幅の空き
    Gap(Length),
    /// 行の残りを埋める空き
    Fill,
    /// 行の中で折り返す
    Newline,
    /// 段落の切れ目
    Break,
    /// 装いを変えたまとまり
    Face {face: Face, body: Vec<Node>},
    /// 大きさを変えたまとまり。scale は本文に対する倍率
    Size {scale: f64, body: Vec<Node>},
    /// 下線
    Underline(Vec<Node>),
    /// 途中で切らないまとまり。frame が真なら囲みの線を引く
    Boxed {body: Vec<Node>, frame: bool},
    /// 決まった幅で組んで、文中に置くまとまり。`minipage`
    Fixed {width: Length, body: Vec<Node>},
    /// ふりがな。base の上に text を小さく載せる
    Ruby {base: Vec<Node>, text: Vec<Node>},
    /// 決まった大きさの塗りつぶし。`\rule`
    Bar {width: Length, height: Length, lift: Length},
    /// 脚注の印だけを置く
    FootnoteMark,
    /// 脚注の中身だけを置く
    FootnoteText(Vec<Node>),
    /// 数式
    Math {row: Vec<MathRow>, display: bool},
    /// 化学式
    Chem {source: String, display: bool},
    /// そのまま出す文字列
    Verbatim {text: String, block: bool},
    /// 見出し
    Heading {
        /// 0 が part、1 が chapter、2 が section、3 が subsection、4 が subsubsection
        level: usize,
        numbered: bool,
        title: Vec<Node>,
        /// 振られた番号。[`crate::number`] が書き込む
        number: String,
    },
    /// 引くための名前を、直前の番号に結び付ける
    Label(String),
    /// 番号かページを引く
    Cross {name: String, page: bool},
    /// 参考文献を引く
    Citation(Vec<String>),
    /// 脚注
    Footnote(Vec<Node>),
    /// 箇条書き
    List {kind: ListKind, item: Vec<Item>},
    /// 引用
    Quote(Vec<Node>),
    /// 揃え方を変えたまとまり。spaced は前後に空きを入れるか
    Aligned {align: Align, body: Vec<Node>, spaced: bool},
    /// 表
    Table(Table),
    /// 浮かせるもの
    Float {kind: FloatKind, placement: String, body: Vec<Node>},
    /// 図表の説明。番号は [`crate::number`] が書き込む
    Caption {body: Vec<Node>, number: String, kind: FloatKind},
    /// 画像
    Image {path: String, width: Option<Length>, height: Option<Length>, scale: Option<f64>},
    /// 目次を置く
    Contents,
    /// 標題を置く
    Title,
    /// 参考文献の一覧
    Bibliography(Vec<Reference>),
    /// 縦の空き
    Skip(Length),
    /// 段落の先頭を下げない
    NoIndent,
    /// ここから先の見出し番号を A, B, C にする
    Appendix,
    /// 改ページ
    NewPage,
}


/// 木をたどって、それぞれの要素に手を入れる
///
/// 番号を振るときと、参照を解くときに使う。子を持つ要素は子へも降りる
pub fn walk(body: &mut Vec<Node>, visit: &mut dyn FnMut(&mut Node)) {
    for node in body.iter_mut() {
        visit(node);
        walk_children(node, visit);
    }
}


fn walk_children(node: &mut Node, visit: &mut dyn FnMut(&mut Node)) {
    match node {
        Node::Face {body, ..}
        | Node::Size {body, ..}
        | Node::Underline(body)
        | Node::Boxed {body, ..}
        | Node::Fixed {body, ..}
        | Node::Quote(body)
        | Node::Aligned {body, ..}
        | Node::Float {body, ..}
        | Node::FootnoteText(body)
        | Node::Footnote(body) => walk(body, visit),
        Node::Heading {title, ..} => walk(title, visit),
        Node::Ruby {base, text} => {
            walk(base, visit);
            walk(text, visit);
        }
        Node::Caption {body, ..} => walk(body, visit),
        Node::List {item, ..} => {
            for one in item.iter_mut() {
                if let Some(mark) = one.mark.as_mut() {
                    walk(mark, visit);
                }

                walk(&mut one.body, visit);
            }
        }
        Node::Table(table) => {
            for row in table.row.iter_mut() {
                for cell in row.cell.iter_mut() {
                    walk(&mut cell.body, visit);
                }
            }
        }
        Node::Bibliography(entry) => {
            for one in entry.iter_mut() {
                walk(&mut one.body, visit);
            }
        }
        _ => {}
    }
}


/// 木から地の文だけを取り出す。目次と栞に使う
pub fn plain(body: &[Node]) -> String {
    let mut out = String::new();

    for node in body {
        match node {
            Node::Text(text) => out.push_str(text),
            Node::Space | Node::HardSpace | Node::Gap(_) => out.push(' '),
            Node::Verbatim {text, ..} => out.push_str(text),
            Node::Face {body, ..}
            | Node::Size {body, ..}
            | Node::Underline(body)
            | Node::Boxed {body, ..}
            | Node::Fixed {body, ..} => out.push_str(&plain(body)),
            // ふりがなは読みなので、目次や栞には親文字だけを出す
            Node::Ruby {base, ..} => out.push_str(&plain(base)),
            Node::Math {row, ..} => {
                for one in row {
                    out.push_str(&one.part.join(" "));
                }
            }
            _ => {}
        }
    }

    out
}