panache_parser/syntax/
tables.rs1use super::ast::{AstChildren, support};
4use super::{AstNode, PanacheLanguage, SyntaxKind, SyntaxNode};
5
6pub struct PipeTable(SyntaxNode);
7
8impl AstNode for PipeTable {
9 type Language = PanacheLanguage;
10
11 fn can_cast(kind: SyntaxKind) -> bool {
12 kind == SyntaxKind::PIPE_TABLE
13 }
14
15 fn cast(syntax: SyntaxNode) -> Option<Self> {
16 if Self::can_cast(syntax.kind()) {
17 Some(Self(syntax))
18 } else {
19 None
20 }
21 }
22
23 fn syntax(&self) -> &SyntaxNode {
24 &self.0
25 }
26}
27
28impl PipeTable {
29 pub fn caption(&self) -> Option<TableCaption> {
31 support::child(&self.0)
32 }
33
34 pub fn rows(&self) -> AstChildren<TableRow> {
36 support::children(&self.0)
37 }
38}
39
40pub enum Table {
41 Pipe(PipeTable),
42 Grid(GridTable),
43 Simple(SimpleTable),
44 Multiline(MultilineTable),
45}
46
47impl Table {
48 pub fn cast(syntax: SyntaxNode) -> Option<Self> {
49 if let Some(table) = PipeTable::cast(syntax.clone()) {
50 return Some(Self::Pipe(table));
51 }
52 if let Some(table) = GridTable::cast(syntax.clone()) {
53 return Some(Self::Grid(table));
54 }
55 if let Some(table) = SimpleTable::cast(syntax.clone()) {
56 return Some(Self::Simple(table));
57 }
58 MultilineTable::cast(syntax).map(Self::Multiline)
59 }
60
61 pub fn syntax(&self) -> &SyntaxNode {
62 match self {
63 Self::Pipe(table) => table.syntax(),
64 Self::Grid(table) => table.syntax(),
65 Self::Simple(table) => table.syntax(),
66 Self::Multiline(table) => table.syntax(),
67 }
68 }
69
70 pub fn caption(&self) -> Option<TableCaption> {
71 match self {
72 Self::Pipe(table) => table.caption(),
73 Self::Grid(table) => table.caption(),
74 Self::Simple(table) => table.caption(),
75 Self::Multiline(table) => table.caption(),
76 }
77 }
78}
79
80pub struct GridTable(SyntaxNode);
81
82impl AstNode for GridTable {
83 type Language = PanacheLanguage;
84
85 fn can_cast(kind: SyntaxKind) -> bool {
86 kind == SyntaxKind::GRID_TABLE
87 }
88
89 fn cast(syntax: SyntaxNode) -> Option<Self> {
90 if Self::can_cast(syntax.kind()) {
91 Some(Self(syntax))
92 } else {
93 None
94 }
95 }
96
97 fn syntax(&self) -> &SyntaxNode {
98 &self.0
99 }
100}
101
102impl GridTable {
103 pub fn caption(&self) -> Option<TableCaption> {
105 support::child(&self.0)
106 }
107
108 pub fn rows(&self) -> AstChildren<TableRow> {
110 support::children(&self.0)
111 }
112}
113
114pub struct SimpleTable(SyntaxNode);
115
116impl AstNode for SimpleTable {
117 type Language = PanacheLanguage;
118
119 fn can_cast(kind: SyntaxKind) -> bool {
120 kind == SyntaxKind::SIMPLE_TABLE
121 }
122
123 fn cast(syntax: SyntaxNode) -> Option<Self> {
124 if Self::can_cast(syntax.kind()) {
125 Some(Self(syntax))
126 } else {
127 None
128 }
129 }
130
131 fn syntax(&self) -> &SyntaxNode {
132 &self.0
133 }
134}
135
136impl SimpleTable {
137 pub fn caption(&self) -> Option<TableCaption> {
139 support::child(&self.0)
140 }
141
142 pub fn rows(&self) -> AstChildren<TableRow> {
144 support::children(&self.0)
145 }
146}
147
148pub struct MultilineTable(SyntaxNode);
149
150impl AstNode for MultilineTable {
151 type Language = PanacheLanguage;
152
153 fn can_cast(kind: SyntaxKind) -> bool {
154 kind == SyntaxKind::MULTILINE_TABLE
155 }
156
157 fn cast(syntax: SyntaxNode) -> Option<Self> {
158 if Self::can_cast(syntax.kind()) {
159 Some(Self(syntax))
160 } else {
161 None
162 }
163 }
164
165 fn syntax(&self) -> &SyntaxNode {
166 &self.0
167 }
168}
169
170impl MultilineTable {
171 pub fn caption(&self) -> Option<TableCaption> {
173 support::child(&self.0)
174 }
175
176 pub fn rows(&self) -> AstChildren<TableRow> {
178 support::children(&self.0)
179 }
180}
181
182pub struct TableCaption(SyntaxNode);
183
184impl AstNode for TableCaption {
185 type Language = PanacheLanguage;
186
187 fn can_cast(kind: SyntaxKind) -> bool {
188 kind == SyntaxKind::TABLE_CAPTION
189 }
190
191 fn cast(syntax: SyntaxNode) -> Option<Self> {
192 if Self::can_cast(syntax.kind()) {
193 Some(Self(syntax))
194 } else {
195 None
196 }
197 }
198
199 fn syntax(&self) -> &SyntaxNode {
200 &self.0
201 }
202}
203
204impl TableCaption {
205 pub fn text(&self) -> String {
207 self.0
208 .descendants_with_tokens()
209 .filter_map(|it| it.into_token())
210 .filter(|token| token.kind() == SyntaxKind::TEXT)
211 .map(|token| token.text().to_string())
212 .collect()
213 }
214}
215
216pub struct TableRow(SyntaxNode);
217
218impl AstNode for TableRow {
219 type Language = PanacheLanguage;
220
221 fn can_cast(kind: SyntaxKind) -> bool {
222 kind == SyntaxKind::TABLE_ROW
223 }
224
225 fn cast(syntax: SyntaxNode) -> Option<Self> {
226 if Self::can_cast(syntax.kind()) {
227 Some(Self(syntax))
228 } else {
229 None
230 }
231 }
232
233 fn syntax(&self) -> &SyntaxNode {
234 &self.0
235 }
236}
237
238impl TableRow {
239 pub fn cells(&self) -> AstChildren<TableCell> {
241 support::children(&self.0)
242 }
243}
244
245pub struct TableCell(SyntaxNode);
246
247impl AstNode for TableCell {
248 type Language = PanacheLanguage;
249
250 fn can_cast(kind: SyntaxKind) -> bool {
251 kind == SyntaxKind::TABLE_CELL
252 }
253
254 fn cast(syntax: SyntaxNode) -> Option<Self> {
255 if Self::can_cast(syntax.kind()) {
256 Some(Self(syntax))
257 } else {
258 None
259 }
260 }
261
262 fn syntax(&self) -> &SyntaxNode {
263 &self.0
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use super::*;
270
271 #[test]
272 fn table_wrapper_casts_pipe_table_and_reads_caption() {
273 let input = "| a | b |\n|---|---|\n| 1 | 2 |\n: Caption\n";
274 let tree = crate::parse(input, None);
275 let node = tree
276 .descendants()
277 .find(|n| n.kind() == SyntaxKind::PIPE_TABLE)
278 .expect("pipe table node");
279
280 let table = Table::cast(node).expect("table wrapper");
281 assert_eq!(
282 table.caption().map(|caption| caption.text()),
283 Some("Caption".to_string())
284 );
285 }
286
287 #[test]
288 fn table_wrapper_does_not_cast_non_table_nodes() {
289 let tree = crate::parse("Paragraph\n", None);
290 let paragraph = tree
291 .descendants()
292 .find(|n| n.kind() == SyntaxKind::PARAGRAPH)
293 .expect("paragraph node");
294 assert!(Table::cast(paragraph).is_none());
295 }
296}