lang_util/node/
display.rs1use std::fmt;
2
3use text_size::TextSize;
4
5use crate::FileId;
6
7#[derive(Clone, Copy)]
9pub struct NodeDisplayWrapper<'a, T: ?Sized> {
10 node: &'a T,
11 current_level: usize,
12}
13
14impl NodeDisplayWrapper<'static, str> {
15 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 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
95pub trait NodeContentDisplay {
97 fn name() -> Option<&'static str>;
104
105 fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
111
112 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
148pub trait NodeDisplay: Sized {
150 fn name() -> Option<&'static str>;
152
153 fn start(&self) -> Option<TextSize>;
155 fn end(&self) -> Option<TextSize>;
157 fn source_id(&self) -> Option<FileId>;
159
160 fn display(&self) -> NodeDisplayWrapper<Self>;
162
163 fn display_extra(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
169
170 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}