render_tree/
debug.rs

1use crate::stylesheet::WriteStyle;
2use crate::Document;
3use crate::{Node, PadItem};
4use crate::{Style, Stylesheet};
5use std::{fmt, io};
6use termcolor::WriteColor;
7
8struct DebugDocument<'a, C: WriteColor + 'a> {
9    document: &'a Document,
10    writer: &'a mut C,
11    stylesheet: &'a Stylesheet,
12    line_start: bool,
13    nesting: Vec<&'static str>,
14}
15
16impl<'a, C: WriteColor + 'a> DebugDocument<'a, C> {
17    fn write_document(mut self) -> io::Result<()> {
18        let tree = match self.document.tree() {
19            None => return Ok(()),
20            Some(nodes) => nodes,
21        };
22
23        self.writer.reset()?;
24
25        for item in tree.clone() {
26            match item {
27                Node::Text(string) => self.write_text(string)?,
28                Node::OpenSection(section) => self.write_open_section(section)?,
29                Node::CloseSection => self.write_close_section()?,
30                Node::Newline => self.write_newline()?,
31            }
32        }
33
34        write!(self.writer, "\n\n")?;
35
36        Ok(())
37    }
38
39    fn write_text(&mut self, string: &str) -> io::Result<()> {
40        if self.line_start {
41            self.start_line()?;
42            self.styled_write("|", "fg: black; weight: bold")?;
43        }
44
45        self.write(string)?;
46        self.line_start = false;
47
48        Ok(())
49    }
50
51    fn write_open_section(&mut self, section: &'static str) -> io::Result<()> {
52        self.start_line()?;
53        self.write("<")?;
54
55        self.nesting.push(section);
56        let style = self.stylesheet.get(&self.nesting[..]);
57
58        self.styled_write(section, "fg: blue; weight: bold")?;
59
60        if let Some(style) = style {
61            if style.has_value() {
62                self.write(" ")?;
63                let debug_attributes = style.debug_attributes();
64                let last = debug_attributes.len() - 1;
65
66                for (i, (name, value)) in debug_attributes.iter().enumerate() {
67                    self.styled_write(name, "fg: black; weight: bold")?;
68
69                    if let Some(value) = value {
70                        self.write("=")?;
71                        self.styled_write(value, "fg: cyan; weight: dim")?;
72                    }
73
74                    if i != last {
75                        self.write(" ")?;
76                    }
77                }
78
79                self.styled_write(" ยง", style)?;
80            }
81        }
82
83        self.writer.reset()?;
84        write!(self.writer, ">")?;
85        self.line_start = true;
86
87        Ok(())
88    }
89
90    fn write_close_section(&mut self) -> io::Result<()> {
91        let popped = self.nesting.pop().expect("unbalanced push/pop");
92        self.start_line()?;
93        write!(self.writer, "</")?;
94
95        self.writer.set_style(&Style("fg: blue; weight: bold"))?;
96        write!(self.writer, "{}", popped)?;
97        self.writer.reset()?;
98        write!(self.writer, ">")?;
99        self.line_start = true;
100
101        Ok(())
102    }
103
104    fn write_newline(&mut self) -> io::Result<()> {
105        let writer = &mut self.writer;
106        writer.reset()?;
107
108        if self.line_start {
109            write!(writer, "\n{}", PadItem("  ", self.nesting.len()))?;
110        }
111
112        write!(writer, "\\n",)?;
113        self.line_start = true;
114
115        Ok(())
116    }
117
118    fn start_line(&mut self) -> io::Result<()> {
119        let pad = self.pad();
120        write!(self.writer, "\n{}", pad)
121    }
122
123    fn styled_write(
124        &mut self,
125        value: impl fmt::Display,
126        style: impl Into<Style>,
127    ) -> io::Result<()> {
128        self.writer.set_style(style)?;
129        self.write(value)?;
130        self.writer.reset()
131    }
132
133    fn write(&mut self, value: impl fmt::Display) -> io::Result<()> {
134        write!(self.writer, "{}", value)
135    }
136
137    fn pad(&self) -> PadItem<&'static str> {
138        PadItem(" ", self.nesting.len())
139    }
140}
141
142impl Document {
143    pub fn debug_write(
144        &self,
145        writer: &mut impl WriteColor,
146        stylesheet: &Stylesheet,
147    ) -> io::Result<()> {
148        DebugDocument {
149            document: self,
150            writer,
151            stylesheet,
152            line_start: true,
153            nesting: vec![],
154        }.write_document()
155    }
156}