rust_code_analysis/output/
dump.rs1use std::io::Write;
2use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, StandardStreamLock, WriteColor};
3
4use crate::node::Node;
5
6use crate::traits::*;
7
8pub fn dump_node(
37 code: &[u8],
38 node: &Node,
39 depth: i32,
40 line_start: Option<usize>,
41 line_end: Option<usize>,
42) -> std::io::Result<()> {
43 let stdout = StandardStream::stdout(ColorChoice::Always);
44 let mut stdout = stdout.lock();
45 let ret = dump_tree_helper(
46 code,
47 node,
48 "",
49 true,
50 &mut stdout,
51 depth,
52 &line_start,
53 &line_end,
54 );
55
56 color!(stdout, White);
57
58 ret
59}
60
61#[allow(clippy::too_many_arguments)]
62fn dump_tree_helper(
63 code: &[u8],
64 node: &Node,
65 prefix: &str,
66 last: bool,
67 stdout: &mut StandardStreamLock,
68 depth: i32,
69 line_start: &Option<usize>,
70 line_end: &Option<usize>,
71) -> std::io::Result<()> {
72 if depth == 0 {
73 return Ok(());
74 }
75
76 let (pref_child, pref) = if node.object().parent().is_none() {
77 ("", "")
78 } else if last {
79 (" ", "╰─ ")
80 } else {
81 ("│ ", "├─ ")
82 };
83
84 let node_row = node.object().start_position().row + 1;
85 let mut display = true;
86 if let Some(line_start) = line_start {
87 display = node_row >= *line_start
88 }
89 if let Some(line_end) = line_end {
90 display = display && node_row <= *line_end
91 }
92
93 if display {
94 color!(stdout, Blue);
95 write!(stdout, "{}{}", prefix, pref)?;
96
97 color!(stdout, Yellow, true);
98 write!(
99 stdout,
100 "{{{}:{}}} ",
101 node.object().kind(),
102 node.object().kind_id()
103 )?;
104
105 color!(stdout, White);
106 write!(stdout, "from ")?;
107
108 color!(stdout, Green);
109 let pos = node.object().start_position();
110 write!(stdout, "({}, {}) ", pos.row + 1, pos.column + 1)?;
111
112 color!(stdout, White);
113 write!(stdout, "to ")?;
114
115 color!(stdout, Green);
116 let pos = node.object().end_position();
117 write!(stdout, "({}, {}) ", pos.row + 1, pos.column + 1)?;
118
119 if node.object().start_position().row == node.object().end_position().row {
120 color!(stdout, White);
121 write!(stdout, ": ")?;
122
123 color!(stdout, Red, true);
124 let code = &code[node.object().start_byte()..node.object().end_byte()];
125 if let Ok(code) = String::from_utf8(code.to_vec()) {
126 write!(stdout, "{} ", code)?;
127 } else {
128 stdout.write_all(code).unwrap();
129 }
130 }
131
132 writeln!(stdout)?;
133 }
134
135 let count = node.object().child_count();
136 if count != 0 {
137 let prefix = format!("{}{}", prefix, pref_child);
138 let mut i = count;
139 let mut cursor = node.object().walk();
140 cursor.goto_first_child();
141
142 loop {
143 i -= 1;
144 dump_tree_helper(
145 code,
146 &Node::new(cursor.node()),
147 &prefix,
148 i == 0,
149 stdout,
150 depth - 1,
151 line_start,
152 line_end,
153 )?;
154 if !cursor.goto_next_sibling() {
155 break;
156 }
157 }
158 }
159
160 Ok(())
161}
162
163pub struct DumpCfg {
165 pub line_start: Option<usize>,
170 pub line_end: Option<usize>,
175}
176
177pub struct Dump {
178 _guard: (),
179}
180
181impl Callback for Dump {
182 type Res = std::io::Result<()>;
183 type Cfg = DumpCfg;
184
185 fn call<T: ParserTrait>(cfg: Self::Cfg, parser: &T) -> Self::Res {
186 dump_node(
187 parser.get_code(),
188 &parser.get_root(),
189 -1,
190 cfg.line_start,
191 cfg.line_end,
192 )
193 }
194}