org_rust_parser/element/
table.rs1use crate::constants::{HYPHEN, NEWLINE};
2use crate::node_pool::NodeID;
3use crate::object::TableCell;
4use crate::types::{Cursor, Expr, MarkupKind, ParseOpts, Parseable, Parser, Result};
5
6#[derive(Debug, Clone)]
11pub struct Table {
12 pub rows: usize,
13 pub cols: usize,
14 pub children: Vec<NodeID>,
15 pub caption: Option<NodeID>, }
17
18#[derive(Debug, Clone)]
36pub enum TableRow {
37 Rule, Standard(Vec<NodeID>),
39}
40
41impl<'a> Parseable<'a> for Table {
42 fn parse(
43 parser: &mut Parser<'a>,
44 mut cursor: Cursor<'a>,
45 parent: Option<NodeID>,
46 mut parse_opts: ParseOpts,
47 ) -> Result<NodeID> {
48 let start = cursor.index;
49
50 parse_opts.markup.insert(MarkupKind::Table);
52 let reserve_id = parser.pool.reserve_id();
53 let mut children: Vec<NodeID> = Vec::new();
54 let mut rows = 0;
55 let mut cols = 0;
56 while let Ok(row_id) = TableRow::parse(parser, cursor, Some(reserve_id), parse_opts) {
57 let obj = &parser.pool[row_id];
58
59 children.push(row_id);
60 rows += 1;
61 if let Expr::TableRow(TableRow::Standard(node_ids)) = &obj.obj {
62 cols = cols.max(node_ids.len());
63 }
64
65 cursor.index = parser.pool[row_id].end;
66 }
67
68 Ok(parser.alloc_with_id(
69 Self {
70 rows,
71 cols,
72 children,
73 caption: None,
74 },
75 start,
76 cursor.index,
77 parent,
78 reserve_id,
79 ))
80 }
81}
82
83impl<'a> Parseable<'a> for TableRow {
84 fn parse(
85 parser: &mut Parser<'a>,
86 mut cursor: Cursor<'a>,
87 parent: Option<NodeID>,
88 parse_opts: ParseOpts,
89 ) -> Result<NodeID> {
90 let start = cursor.index;
91
92 cursor.curr_valid()?;
96 cursor.skip_ws();
97 cursor.word("|")?;
98
99 if let Ok(val) = cursor.try_curr()
107 && val == HYPHEN
108 {
109 cursor.adv_till_byte(b'\n');
111 return Ok(parser
113 .pool
114 .alloc(Self::Rule, start, cursor.index + 1, parent));
115 }
116
117 let mut children: Vec<NodeID> = Vec::new();
118 while let Ok(table_cell_id) = TableCell::parse(parser, cursor, parent, parse_opts) {
119 let node_item = &parser.pool[table_cell_id];
120 children.push(table_cell_id);
121
122 cursor.index = node_item.end;
123 if let Ok(val) = cursor.try_curr() {
124 if val == NEWLINE {
125 cursor.next();
126 break;
127 }
128 } else {
129 break;
130 }
131 }
132
133 Ok(parser
134 .pool
135 .alloc(Self::Standard(children), start, cursor.index, parent))
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use crate::{Expr, element::Affiliated, expr_in_pool, parse_org};
142
143 #[test]
144 fn basic_table() {
145 let input = r"
146|one|two|
147|three|four|
148";
149 let pool = parse_org(input);
150
151 pool.print_tree();
152 }
153
154 #[test]
155 fn table_eof_1() {
156 let input = r"
157|one|two|
158|three|four|
159";
160 let pool = parse_org(input);
161
162 pool.print_tree();
163 }
164
165 #[test]
166 fn table_eof_2() {
167 let input = r"
168|one|two|
169|three|four|";
170 let pool = parse_org(input);
171
172 pool.print_tree();
173 }
174
175 #[test]
176 fn table_no_nl() {
177 let input = r"
178|one|two
179|three|four
180
181";
182 let pool = parse_org(input);
183
184 pool.print_tree();
185 }
186
187 #[test]
188 fn table_with_hrule() {
189 let input = r"
190|one|two
191|--------|
192|three|four
193
194";
195 let pool = parse_org(input);
196
197 pool.print_tree();
198 }
199
200 #[test]
201 fn table_markup_1() {
202 let input = r"
203|one|tw *o* |
204|three|four|
205";
206 let pool = parse_org(input);
207
208 pool.print_tree();
209 }
210
211 #[test]
212 fn table_empty_cells() {
213 let input = r"
214||a|
215|b||
216";
217 let pool = parse_org(input);
218
219 pool.print_tree();
220 }
221
222 #[test]
224 fn table_aligned_cells() {
225 let input = r"
226|one two |three|
227|s | |
228";
229
230 let pool = parse_org(input);
231
232 pool.print_tree();
233 }
234
235 #[test]
236 fn table_uneven_cols() {
237 let input = r"
238|one two |three|||||
239|s | |
240";
241
242 let pool = parse_org(input);
243
244 pool.print_tree();
245 }
246
247 #[test]
248 fn table_indented() {
249 let input = r"
250word
251 |one two |three|
252 |s | |
253 |four | five|
254word
255
256";
257
258 let pool = parse_org(input);
259 pool.print_tree();
260 }
261
262 #[test]
263 fn table_indented_list() {
264 let input = r"
265- one
266 - two
267 |one two |three|
268 |s | |
269 |four | five|
270- three
271";
272
273 let pool = parse_org(input);
274
275 pool.print_tree();
276 }
277
278 #[test]
279 fn table_no_start() {
280 let input = r"|";
281
282 let pool = parse_org(input);
283 let tab = expr_in_pool!(pool, Table).unwrap();
284 assert_eq!(tab.rows, 1);
285 }
286
287 #[test]
288 fn table_caption() {
289 let input = r"
290#+caption: i am a table
291|a|b|c
292
293";
294
295 let parser = parse_org(input);
296 let image_link = expr_in_pool!(parser, Table).unwrap();
297 if let Some(cap_id) = image_link.caption
298 && let Expr::Affiliated(Affiliated::Caption(aff)) = &parser.pool[cap_id].obj
299 && let Expr::Paragraph(par) = &parser.pool[*aff].obj
300 && let Expr::Plain(text) = parser.pool[par.0[0]].obj
301 {
302 assert_eq!(text, " i am a table");
303 } else {
304 panic!()
305 };
306 }
307}