1use std::io::Write;
2use termcolor::{Color, ColorChoice, StandardStream, StandardStreamLock};
3
4use crate::cognitive;
5use crate::cyclomatic;
6use crate::exit;
7use crate::halstead;
8use crate::loc;
9use crate::mi;
10use crate::nargs;
11use crate::nom;
12
13use crate::spaces::{CodeMetrics, FuncSpace};
14
15use crate::tools::{color, intense_color};
16
17pub fn dump_root(space: &FuncSpace) -> std::io::Result<()> {
46 let stdout = StandardStream::stdout(ColorChoice::Always);
47 let mut stdout = stdout.lock();
48 dump_space(space, "", true, &mut stdout)?;
49 color(&mut stdout, Color::White)?;
50
51 Ok(())
52}
53
54fn dump_space(
55 space: &FuncSpace,
56 prefix: &str,
57 last: bool,
58 stdout: &mut StandardStreamLock,
59) -> std::io::Result<()> {
60 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
61
62 color(stdout, Color::Blue)?;
63 write!(stdout, "{prefix}{pref}")?;
64
65 intense_color(stdout, Color::Yellow)?;
66 write!(stdout, "{}: ", space.kind)?;
67
68 intense_color(stdout, Color::Cyan)?;
69 write!(stdout, "{}", space.name.as_ref().map_or("", |name| name))?;
70
71 intense_color(stdout, Color::Red)?;
72 writeln!(stdout, " (@{})", space.start_line)?;
73
74 let prefix = format!("{prefix}{pref_child}");
75 dump_metrics(&space.metrics, &prefix, space.spaces.is_empty(), stdout)?;
76
77 if let Some((last, spaces)) = space.spaces.split_last() {
78 for space in spaces {
79 dump_space(space, &prefix, false, stdout)?;
80 }
81 dump_space(last, &prefix, true, stdout)?;
82 }
83
84 Ok(())
85}
86
87fn dump_metrics(
88 metrics: &CodeMetrics,
89 prefix: &str,
90 last: bool,
91 stdout: &mut StandardStreamLock,
92) -> std::io::Result<()> {
93 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
94
95 color(stdout, Color::Blue)?;
96 write!(stdout, "{prefix}{pref}")?;
97
98 intense_color(stdout, Color::Yellow)?;
99 writeln!(stdout, "metrics")?;
100
101 let prefix = format!("{prefix}{pref_child}");
102 dump_cognitive(&metrics.cognitive, &prefix, false, stdout)?;
103 dump_cyclomatic(&metrics.cyclomatic, &prefix, false, stdout)?;
104 dump_nargs(&metrics.nargs, &prefix, false, stdout)?;
105 dump_nexits(&metrics.nexits, &prefix, false, stdout)?;
106 dump_halstead(&metrics.halstead, &prefix, false, stdout)?;
107 dump_loc(&metrics.loc, &prefix, false, stdout)?;
108 dump_nom(&metrics.nom, &prefix, false, stdout)?;
109 dump_mi(&metrics.mi, &prefix, true, stdout)
110}
111
112fn dump_cognitive(
113 stats: &cognitive::Stats,
114 prefix: &str,
115 last: bool,
116 stdout: &mut StandardStreamLock,
117) -> std::io::Result<()> {
118 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
119
120 color(stdout, Color::Blue)?;
121 write!(stdout, "{prefix}{pref}")?;
122
123 intense_color(stdout, Color::Green)?;
124 writeln!(stdout, "cognitive")?;
125
126 let prefix = format!("{prefix}{pref_child}");
127
128 dump_value("sum", stats.cognitive(), &prefix, false, stdout)?;
129 dump_value("average", stats.cognitive_average(), &prefix, true, stdout)
130}
131
132fn dump_cyclomatic(
133 stats: &cyclomatic::Stats,
134 prefix: &str,
135 last: bool,
136 stdout: &mut StandardStreamLock,
137) -> std::io::Result<()> {
138 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
139
140 color(stdout, Color::Blue)?;
141 write!(stdout, "{prefix}{pref}")?;
142
143 intense_color(stdout, Color::Green)?;
144 writeln!(stdout, "cyclomatic")?;
145
146 let prefix = format!("{prefix}{pref_child}");
147
148 dump_value("sum", stats.cyclomatic(), &prefix, false, stdout)?;
149 dump_value("average", stats.cyclomatic_average(), &prefix, true, stdout)
150}
151
152fn dump_halstead(
153 stats: &halstead::Stats,
154 prefix: &str,
155 last: bool,
156 stdout: &mut StandardStreamLock,
157) -> std::io::Result<()> {
158 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
159
160 color(stdout, Color::Blue)?;
161 write!(stdout, "{prefix}{pref}")?;
162
163 intense_color(stdout, Color::Green)?;
164 writeln!(stdout, "halstead")?;
165
166 let prefix = format!("{prefix}{pref_child}");
167
168 dump_value("n1", stats.u_operators(), &prefix, false, stdout)?;
169 dump_value("N1", stats.operators(), &prefix, false, stdout)?;
170 dump_value("n2", stats.u_operands(), &prefix, false, stdout)?;
171 dump_value("N2", stats.operands(), &prefix, false, stdout)?;
172
173 dump_value("length", stats.length(), &prefix, false, stdout)?;
174 dump_value(
175 "estimated program length",
176 stats.estimated_program_length(),
177 &prefix,
178 false,
179 stdout,
180 )?;
181 dump_value("purity ratio", stats.purity_ratio(), &prefix, false, stdout)?;
182 dump_value("vocabulary", stats.vocabulary(), &prefix, false, stdout)?;
183 dump_value("volume", stats.volume(), &prefix, false, stdout)?;
184 dump_value("difficulty", stats.difficulty(), &prefix, false, stdout)?;
185 dump_value("level", stats.level(), &prefix, false, stdout)?;
186 dump_value("effort", stats.effort(), &prefix, false, stdout)?;
187 dump_value("time", stats.time(), &prefix, false, stdout)?;
188 dump_value("bugs", stats.bugs(), &prefix, true, stdout)
189}
190
191fn dump_loc(
192 stats: &loc::Stats,
193 prefix: &str,
194 last: bool,
195 stdout: &mut StandardStreamLock,
196) -> std::io::Result<()> {
197 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
198
199 color(stdout, Color::Blue)?;
200 write!(stdout, "{prefix}{pref}")?;
201
202 intense_color(stdout, Color::Green)?;
203 writeln!(stdout, "loc")?;
204
205 let prefix = format!("{prefix}{pref_child}");
206 dump_value("sloc", stats.sloc(), &prefix, false, stdout)?;
207 dump_value("ploc", stats.ploc(), &prefix, false, stdout)?;
208 dump_value("lloc", stats.lloc(), &prefix, false, stdout)?;
209 dump_value("cloc", stats.cloc(), &prefix, false, stdout)?;
210 dump_value("blank", stats.blank(), &prefix, true, stdout)
211}
212
213fn dump_nom(
214 stats: &nom::Stats,
215 prefix: &str,
216 last: bool,
217 stdout: &mut StandardStreamLock,
218) -> std::io::Result<()> {
219 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
220
221 color(stdout, Color::Blue)?;
222 write!(stdout, "{prefix}{pref}")?;
223
224 intense_color(stdout, Color::Green)?;
225 writeln!(stdout, "nom")?;
226
227 let prefix = format!("{prefix}{pref_child}");
228 dump_value("functions", stats.functions(), &prefix, false, stdout)?;
229 dump_value("closures", stats.closures(), &prefix, false, stdout)?;
230 dump_value("total", stats.total(), &prefix, true, stdout)
231}
232
233fn dump_mi(
234 stats: &mi::Stats,
235 prefix: &str,
236 last: bool,
237 stdout: &mut StandardStreamLock,
238) -> std::io::Result<()> {
239 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
240
241 color(stdout, Color::Blue)?;
242 write!(stdout, "{prefix}{pref}")?;
243
244 intense_color(stdout, Color::Green)?;
245 writeln!(stdout, "mi")?;
246
247 let prefix = format!("{prefix}{pref_child}");
248 dump_value("mi_original", stats.mi_original(), &prefix, false, stdout)?;
249 dump_value("mi_sei", stats.mi_sei(), &prefix, false, stdout)?;
250 dump_value(
251 "mi_visual_studio",
252 stats.mi_visual_studio(),
253 &prefix,
254 true,
255 stdout,
256 )
257}
258
259fn dump_nargs(
260 stats: &nargs::Stats,
261 prefix: &str,
262 last: bool,
263 stdout: &mut StandardStreamLock,
264) -> std::io::Result<()> {
265 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
266
267 color(stdout, Color::Blue)?;
268 write!(stdout, "{prefix}{pref}")?;
269
270 intense_color(stdout, Color::Green)?;
271 writeln!(stdout, "nargs")?;
272
273 let prefix = format!("{prefix}{pref_child}");
274 dump_value("functions", stats.fn_args(), &prefix, false, stdout)?;
275 dump_value("closures", stats.closure_args(), &prefix, false, stdout)?;
276 dump_value("total", stats.nargs_total(), &prefix, false, stdout)?;
277 dump_value("average", stats.nargs_average(), &prefix, true, stdout)
278}
279
280fn dump_nexits(
281 stats: &exit::Stats,
282 prefix: &str,
283 last: bool,
284 stdout: &mut StandardStreamLock,
285) -> std::io::Result<()> {
286 let pref = if last { "`- " } else { "|- " };
287
288 color(stdout, Color::Blue)?;
289 write!(stdout, "{prefix}{pref}")?;
290
291 intense_color(stdout, Color::Green)?;
292 write!(stdout, "nexits: ")?;
293
294 color(stdout, Color::White)?;
295 writeln!(stdout, "{}", stats.exit())
296}
297
298fn dump_value(
299 name: &str,
300 val: f64,
301 prefix: &str,
302 last: bool,
303 stdout: &mut StandardStreamLock,
304) -> std::io::Result<()> {
305 let pref = if last { "`- " } else { "|- " };
306
307 color(stdout, Color::Blue)?;
308 write!(stdout, "{prefix}{pref}")?;
309
310 intense_color(stdout, Color::Magenta)?;
311 write!(stdout, "{name}: ")?;
312
313 color(stdout, Color::White)?;
314 writeln!(stdout, "{val}")
315}