Skip to main content

panache_parser/syntax/
tables.rs

1//! Table AST node wrappers.
2
3use 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    /// Returns the table caption if present.
30    pub fn caption(&self) -> Option<TableCaption> {
31        support::child(&self.0)
32    }
33
34    /// Returns all table rows.
35    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    /// Returns the table caption if present.
104    pub fn caption(&self) -> Option<TableCaption> {
105        support::child(&self.0)
106    }
107
108    /// Returns all table rows.
109    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    /// Returns the table caption if present.
138    pub fn caption(&self) -> Option<TableCaption> {
139        support::child(&self.0)
140    }
141
142    /// Returns all table rows.
143    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    /// Returns the table caption if present.
172    pub fn caption(&self) -> Option<TableCaption> {
173        support::child(&self.0)
174    }
175
176    /// Returns all table rows.
177    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    /// Returns the caption text.
206    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    /// Returns all cells in this row.
240    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}