panache_parser/syntax/
blocks.rs1use super::ast::support;
2use super::{AstNode, ImageLink, PanacheLanguage, SyntaxKind, SyntaxNode};
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub struct Document(SyntaxNode);
6
7impl AstNode for Document {
8 type Language = PanacheLanguage;
9
10 fn can_cast(kind: SyntaxKind) -> bool {
11 kind == SyntaxKind::DOCUMENT
12 }
13
14 fn cast(syntax: SyntaxNode) -> Option<Self> {
15 Self::can_cast(syntax.kind()).then(|| Self(syntax))
16 }
17
18 fn syntax(&self) -> &SyntaxNode {
19 &self.0
20 }
21}
22
23impl Document {
24 pub fn blocks(&self) -> impl Iterator<Item = SyntaxNode> {
25 self.0.children()
26 }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
30pub struct Paragraph(SyntaxNode);
31
32impl AstNode for Paragraph {
33 type Language = PanacheLanguage;
34
35 fn can_cast(kind: SyntaxKind) -> bool {
36 kind == SyntaxKind::PARAGRAPH
37 }
38
39 fn cast(syntax: SyntaxNode) -> Option<Self> {
40 Self::can_cast(syntax.kind()).then(|| Self(syntax))
41 }
42
43 fn syntax(&self) -> &SyntaxNode {
44 &self.0
45 }
46}
47
48impl Paragraph {
49 pub fn image_links(&self) -> impl Iterator<Item = ImageLink> {
50 support::children(&self.0)
51 }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Hash)]
55pub struct Plain(SyntaxNode);
56
57impl AstNode for Plain {
58 type Language = PanacheLanguage;
59
60 fn can_cast(kind: SyntaxKind) -> bool {
61 kind == SyntaxKind::PLAIN
62 }
63
64 fn cast(syntax: SyntaxNode) -> Option<Self> {
65 Self::can_cast(syntax.kind()).then(|| Self(syntax))
66 }
67
68 fn syntax(&self) -> &SyntaxNode {
69 &self.0
70 }
71}
72
73#[derive(Debug, Clone, PartialEq, Eq, Hash)]
74pub struct LineBlock(SyntaxNode);
75
76impl AstNode for LineBlock {
77 type Language = PanacheLanguage;
78
79 fn can_cast(kind: SyntaxKind) -> bool {
80 kind == SyntaxKind::LINE_BLOCK
81 }
82
83 fn cast(syntax: SyntaxNode) -> Option<Self> {
84 Self::can_cast(syntax.kind()).then(|| Self(syntax))
85 }
86
87 fn syntax(&self) -> &SyntaxNode {
88 &self.0
89 }
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Hash)]
93pub struct LineBlockLine(SyntaxNode);
94
95impl AstNode for LineBlockLine {
96 type Language = PanacheLanguage;
97
98 fn can_cast(kind: SyntaxKind) -> bool {
99 kind == SyntaxKind::LINE_BLOCK_LINE
100 }
101
102 fn cast(syntax: SyntaxNode) -> Option<Self> {
103 Self::can_cast(syntax.kind()).then(|| Self(syntax))
104 }
105
106 fn syntax(&self) -> &SyntaxNode {
107 &self.0
108 }
109}
110
111#[derive(Debug, Clone, PartialEq, Eq, Hash)]
112pub struct PandocTitleBlock(SyntaxNode);
113
114impl AstNode for PandocTitleBlock {
115 type Language = PanacheLanguage;
116
117 fn can_cast(kind: SyntaxKind) -> bool {
118 kind == SyntaxKind::PANDOC_TITLE_BLOCK
119 }
120
121 fn cast(syntax: SyntaxNode) -> Option<Self> {
122 Self::can_cast(syntax.kind()).then(|| Self(syntax))
123 }
124
125 fn syntax(&self) -> &SyntaxNode {
126 &self.0
127 }
128}
129
130#[derive(Debug, Clone, PartialEq, Eq, Hash)]
131pub struct MmdTitleBlock(SyntaxNode);
132
133impl AstNode for MmdTitleBlock {
134 type Language = PanacheLanguage;
135
136 fn can_cast(kind: SyntaxKind) -> bool {
137 kind == SyntaxKind::MMD_TITLE_BLOCK
138 }
139
140 fn cast(syntax: SyntaxNode) -> Option<Self> {
141 Self::can_cast(syntax.kind()).then(|| Self(syntax))
142 }
143
144 fn syntax(&self) -> &SyntaxNode {
145 &self.0
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn document_blocks_iterates_top_level_nodes() {
155 let input = "# H1\n\nParagraph\n";
156 let tree = crate::parse(input, None);
157 let document = Document::cast(tree).expect("document");
158 let kinds = document
159 .blocks()
160 .map(|node| node.kind())
161 .collect::<Vec<_>>();
162 assert_eq!(
163 kinds,
164 vec![
165 SyntaxKind::HEADING,
166 SyntaxKind::BLANK_LINE,
167 SyntaxKind::PARAGRAPH
168 ]
169 );
170 }
171
172 #[test]
173 fn paragraph_image_links_extracts_inline_image_nodes() {
174 let input = "See  here.\n";
175 let tree = crate::parse(input, None);
176 let paragraph = tree
177 .descendants()
178 .find_map(Paragraph::cast)
179 .expect("paragraph");
180 let images = paragraph.image_links().collect::<Vec<_>>();
181 assert_eq!(images.len(), 1);
182 assert_eq!(
183 images[0].alt().map(|alt| alt.text()),
184 Some("Alt".to_string())
185 );
186 }
187}