lang_util/node/
display.rs

1use std::fmt;
2
3use text_size::TextSize;
4
5use crate::FileId;
6
7/// A wrapper for a syntax node to be displayed
8#[derive(Clone, Copy)]
9pub struct NodeDisplayWrapper<'a, T: ?Sized> {
10    node: &'a T,
11    current_level: usize,
12}
13
14impl NodeDisplayWrapper<'static, str> {
15    /// Create a new [NodeDisplayWrapper]
16    ///
17    /// # Parameters
18    ///
19    /// * `name`: name of the node being displayed
20    /// * `level`: current indentation level
21    pub fn new(name: &'static str, level: usize) -> Self {
22        Self {
23            node: name,
24            current_level: level,
25        }
26    }
27}
28
29impl fmt::Display for NodeDisplayWrapper<'static, str> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        for _ in 0..self.current_level {
32            write!(f, "  ")?;
33        }
34
35        writeln!(f, "{}", self.node)?;
36
37        Ok(())
38    }
39}
40
41impl<'a, T> NodeDisplayWrapper<'a, T> {
42    /// Set the level of this display wrapper
43    ///
44    /// # Parameters
45    ///
46    /// * `level`: new indentation level
47    ///
48    /// # Returns
49    ///
50    /// New display wrapper with the updated level.
51    pub fn set_level(self, level: usize) -> Self {
52        Self {
53            node: self.node,
54            current_level: level,
55        }
56    }
57}
58
59impl<T: NodeDisplay> fmt::Display for NodeDisplayWrapper<'_, T> {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        if let Some(name) = T::name() {
62            for _ in 0..self.current_level {
63                write!(f, "  ")?;
64            }
65
66            if let (Some(start), Some(end)) = (self.node.start(), self.node.end()) {
67                if let Some(source_id) = self.node.source_id() {
68                    write!(
69                        f,
70                        "{}@{}:{}..{}",
71                        name,
72                        source_id,
73                        u32::from(start),
74                        u32::from(end)
75                    )?;
76                } else {
77                    write!(f, "{}@{}..{}", name, u32::from(start), u32::from(end))?;
78                }
79            } else {
80                write!(f, "{}", name)?;
81            }
82
83            self.node.display_extra(f)?;
84            writeln!(f)?;
85
86            self.node.display_children(self.current_level + 1, f)?;
87        } else {
88            self.node.display_children(self.current_level, f)?;
89        }
90
91        Ok(())
92    }
93}
94
95/// Trait for displaying an AST node's content
96pub trait NodeContentDisplay {
97    /// Name of the node
98    ///
99    /// # Returns
100    ///
101    /// `None` if this node is just a transparent wrapper (and should not be displayed), otherwise
102    /// the name of the node type.
103    fn name() -> Option<&'static str>;
104
105    /// Display extra information for the node
106    ///
107    /// # Parameters
108    ///
109    /// * `f`: formatter to output to
110    fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
111
112    /// Display the node's children
113    ///
114    /// # Parameters
115    ///
116    /// * `level`: current indentation level
117    /// * `f`: formatter to output to
118    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result;
119}
120
121macro_rules! forward_display {
122    ($i:ty => $e:expr) => {
123        impl NodeContentDisplay for $i {
124            fn name() -> Option<&'static str> {
125                Some($e)
126            }
127
128            fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
129                write!(f, " `{}`", self)
130            }
131
132            fn display_children(&self, _level: usize, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
133                Ok(())
134            }
135        }
136    }
137}
138
139forward_display!(smol_str::SmolStr => "String");
140forward_display!(String => "String");
141forward_display!(f32 => "FloatConst");
142forward_display!(f64 => "DoubleConst");
143forward_display!(i32 => "IntConst");
144forward_display!(u16 => "ShortConst");
145forward_display!(u32 => "UIntConst");
146forward_display!(bool => "BoolConst");
147
148/// Trait for displaying a syntax node
149pub trait NodeDisplay: Sized {
150    /// Name of the syntax node's type
151    fn name() -> Option<&'static str>;
152
153    /// Starting position of the node
154    fn start(&self) -> Option<TextSize>;
155    /// Ending position of the node
156    fn end(&self) -> Option<TextSize>;
157    /// Source id of the node
158    fn source_id(&self) -> Option<FileId>;
159
160    /// Obtain a display wrapper for the current node
161    fn display(&self) -> NodeDisplayWrapper<Self>;
162
163    /// Display extra information for the node
164    ///
165    /// # Parameters
166    ///
167    /// * `f`: formatter to output to
168    fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
169
170    /// Display the node's children
171    ///
172    /// # Parameters
173    ///
174    /// * `level`: current indentation level
175    /// * `f`: formatter to output to
176    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result;
177}
178
179impl<T: NodeContentDisplay + super::NodeContent> NodeDisplay for super::Node<T> {
180    fn name() -> Option<&'static str> {
181        T::name()
182    }
183
184    fn start(&self) -> Option<TextSize> {
185        self.span.map(|s| s.start().offset)
186    }
187
188    fn end(&self) -> Option<TextSize> {
189        self.span.map(|s| s.end().offset)
190    }
191
192    fn source_id(&self) -> Option<FileId> {
193        self.span.map(|s| s.source_id())
194    }
195
196    fn display(&self) -> NodeDisplayWrapper<Self> {
197        NodeDisplayWrapper {
198            node: self,
199            current_level: 0,
200        }
201    }
202
203    fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204        (**self).display_extra(f)
205    }
206
207    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
208        (**self).display_children(level, f)
209    }
210}
211
212impl<T: NodeContentDisplay> NodeDisplay for T {
213    fn name() -> Option<&'static str> {
214        T::name()
215    }
216
217    fn start(&self) -> Option<TextSize> {
218        None
219    }
220
221    fn end(&self) -> Option<TextSize> {
222        None
223    }
224
225    fn source_id(&self) -> Option<FileId> {
226        None
227    }
228
229    fn display(&self) -> NodeDisplayWrapper<Self> {
230        NodeDisplayWrapper {
231            node: self,
232            current_level: 0,
233        }
234    }
235
236    fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237        self.display_extra(f)
238    }
239
240    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        self.display_children(level, f)
242    }
243}
244
245impl<T: NodeDisplay> NodeContentDisplay for Box<T> {
246    fn name() -> Option<&'static str> {
247        T::name()
248    }
249
250    fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        (**self).display_extra(f)
252    }
253
254    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
255        (**self).display_children(level, f)
256    }
257}
258
259impl<T: NodeDisplay> NodeContentDisplay for Option<T> {
260    fn name() -> Option<&'static str> {
261        None
262    }
263
264    fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265        if let Some(inner) = self.as_ref() {
266            inner.display_extra(f)
267        } else {
268            Ok(())
269        }
270    }
271
272    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273        if let Some(inner) = self.as_ref() {
274            inner.display_children(level, f)
275        } else {
276            Ok(())
277        }
278    }
279}
280
281impl<T: NodeDisplay> NodeContentDisplay for Vec<T> {
282    fn name() -> Option<&'static str> {
283        None
284    }
285
286    fn display_extra(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        Ok(())
288    }
289
290    fn display_children(&self, level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
291        for item in self.iter() {
292            write!(f, "{}", item.display().set_level(level))?;
293        }
294
295        Ok(())
296    }
297}