1use std::io::Write;
2use termcolor::{Color, ColorChoice, StandardStream, StandardStreamLock};
3
4use crate::abc;
5use crate::cognitive;
6use crate::cyclomatic;
7use crate::exit;
8use crate::halstead;
9use crate::loc;
10use crate::mi;
11use crate::nargs;
12use crate::nom;
13use crate::npa;
14use crate::npm;
15use crate::tokens;
16use crate::wmc;
17
18use crate::spaces::{CodeMetrics, FuncSpace};
19
20use crate::tools::{color, intense_color};
21
22pub fn dump_root(space: &FuncSpace) -> std::io::Result<()> {
49 let stdout = StandardStream::stdout(ColorChoice::Always);
50 let mut stdout = stdout.lock();
51 dump_space(space, "", true, &mut stdout)?;
52 color(&mut stdout, Color::White)?;
53
54 Ok(())
55}
56
57fn dump_space(
58 space: &FuncSpace,
59 prefix: &str,
60 last: bool,
61 stdout: &mut StandardStreamLock,
62) -> std::io::Result<()> {
63 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
64
65 color(stdout, Color::Blue)?;
66 write!(stdout, "{prefix}{pref}")?;
67
68 intense_color(stdout, Color::Yellow)?;
69 write!(stdout, "{}: ", space.kind)?;
70
71 intense_color(stdout, Color::Cyan)?;
72 write!(stdout, "{}", space.name.as_ref().map_or("", |name| name))?;
73
74 intense_color(stdout, Color::Red)?;
75 writeln!(stdout, " (@{})", space.start_line)?;
76
77 let prefix = format!("{prefix}{pref_child}");
78 dump_metrics(&space.metrics, &prefix, space.spaces.is_empty(), stdout)?;
79
80 if let Some((last, spaces)) = space.spaces.split_last() {
81 for space in spaces {
82 dump_space(space, &prefix, false, stdout)?;
83 }
84 dump_space(last, &prefix, true, stdout)?;
85 }
86
87 Ok(())
88}
89
90fn dump_metrics(
91 metrics: &CodeMetrics,
92 prefix: &str,
93 last: bool,
94 stdout: &mut StandardStreamLock,
95) -> std::io::Result<()> {
96 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
97
98 color(stdout, Color::Blue)?;
99 write!(stdout, "{prefix}{pref}")?;
100
101 intense_color(stdout, Color::Yellow)?;
102 writeln!(stdout, "metrics")?;
103
104 let prefix = format!("{prefix}{pref_child}");
105 dump_cognitive(&metrics.cognitive, &prefix, false, stdout)?;
106 dump_cyclomatic(&metrics.cyclomatic, &prefix, false, stdout)?;
107 dump_nargs(&metrics.nargs, &prefix, false, stdout)?;
108 dump_nexits(&metrics.nexits, &prefix, false, stdout)?;
109 dump_halstead(&metrics.halstead, &prefix, false, stdout)?;
110 dump_loc(&metrics.loc, &prefix, false, stdout)?;
111 dump_nom(&metrics.nom, &prefix, false, stdout)?;
112 dump_tokens(&metrics.tokens, &prefix, false, stdout)?;
113 dump_mi(&metrics.mi, &prefix, false, stdout)?;
114 dump_abc(&metrics.abc, &prefix, false, stdout)?;
115 dump_wmc(&metrics.wmc, &prefix, false, stdout)?;
116 dump_npm(&metrics.npm, &prefix, false, stdout)?;
117 dump_npa(&metrics.npa, &prefix, true, stdout)
118}
119
120fn dump_cognitive(
121 stats: &cognitive::Stats,
122 prefix: &str,
123 last: bool,
124 stdout: &mut StandardStreamLock,
125) -> std::io::Result<()> {
126 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
127
128 color(stdout, Color::Blue)?;
129 write!(stdout, "{prefix}{pref}")?;
130
131 intense_color(stdout, Color::Green)?;
132 writeln!(stdout, "cognitive")?;
133
134 let prefix = format!("{prefix}{pref_child}");
135
136 dump_value("sum", stats.cognitive_sum(), &prefix, false, stdout)?;
137 dump_value("average", stats.cognitive_average(), &prefix, true, stdout)
138}
139
140fn dump_cyclomatic(
141 stats: &cyclomatic::Stats,
142 prefix: &str,
143 last: bool,
144 stdout: &mut StandardStreamLock,
145) -> std::io::Result<()> {
146 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
147
148 color(stdout, Color::Blue)?;
149 write!(stdout, "{prefix}{pref}")?;
150
151 intense_color(stdout, Color::Green)?;
152 writeln!(stdout, "cyclomatic")?;
153
154 let prefix = format!("{prefix}{pref_child}");
155
156 dump_value("sum", stats.cyclomatic_sum(), &prefix, false, stdout)?;
157 dump_value("average", stats.cyclomatic_average(), &prefix, true, stdout)
158}
159
160fn dump_halstead(
161 stats: &halstead::Stats,
162 prefix: &str,
163 last: bool,
164 stdout: &mut StandardStreamLock,
165) -> std::io::Result<()> {
166 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
167
168 color(stdout, Color::Blue)?;
169 write!(stdout, "{prefix}{pref}")?;
170
171 intense_color(stdout, Color::Green)?;
172 writeln!(stdout, "halstead")?;
173
174 let prefix = format!("{prefix}{pref_child}");
175
176 dump_value("n1", stats.u_operators(), &prefix, false, stdout)?;
177 dump_value("N1", stats.operators(), &prefix, false, stdout)?;
178 dump_value("n2", stats.u_operands(), &prefix, false, stdout)?;
179 dump_value("N2", stats.operands(), &prefix, false, stdout)?;
180
181 dump_value("length", stats.length(), &prefix, false, stdout)?;
182 dump_value(
183 "estimated program length",
184 stats.estimated_program_length(),
185 &prefix,
186 false,
187 stdout,
188 )?;
189 dump_value("purity ratio", stats.purity_ratio(), &prefix, false, stdout)?;
190 dump_value("vocabulary", stats.vocabulary(), &prefix, false, stdout)?;
191 dump_value("volume", stats.volume(), &prefix, false, stdout)?;
192 dump_value("difficulty", stats.difficulty(), &prefix, false, stdout)?;
193 dump_value("level", stats.level(), &prefix, false, stdout)?;
194 dump_value("effort", stats.effort(), &prefix, false, stdout)?;
195 dump_value("time", stats.time(), &prefix, false, stdout)?;
196 dump_value("bugs", stats.bugs(), &prefix, true, stdout)
197}
198
199fn dump_loc(
200 stats: &loc::Stats,
201 prefix: &str,
202 last: bool,
203 stdout: &mut StandardStreamLock,
204) -> std::io::Result<()> {
205 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
206
207 color(stdout, Color::Blue)?;
208 write!(stdout, "{prefix}{pref}")?;
209
210 intense_color(stdout, Color::Green)?;
211 writeln!(stdout, "loc")?;
212
213 let prefix = format!("{prefix}{pref_child}");
214 dump_value("sloc", stats.sloc(), &prefix, false, stdout)?;
215 dump_value("ploc", stats.ploc(), &prefix, false, stdout)?;
216 dump_value("lloc", stats.lloc(), &prefix, false, stdout)?;
217 dump_value("cloc", stats.cloc(), &prefix, false, stdout)?;
218 dump_value("blank", stats.blank(), &prefix, true, stdout)
219}
220
221fn dump_nom(
222 stats: &nom::Stats,
223 prefix: &str,
224 last: bool,
225 stdout: &mut StandardStreamLock,
226) -> std::io::Result<()> {
227 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
228
229 color(stdout, Color::Blue)?;
230 write!(stdout, "{prefix}{pref}")?;
231
232 intense_color(stdout, Color::Green)?;
233 writeln!(stdout, "nom")?;
234
235 let prefix = format!("{prefix}{pref_child}");
236 dump_value("functions", stats.functions(), &prefix, false, stdout)?;
237 dump_value("closures", stats.closures(), &prefix, false, stdout)?;
238 dump_value("total", stats.total(), &prefix, true, stdout)
239}
240
241fn dump_tokens(
242 stats: &tokens::Stats,
243 prefix: &str,
244 last: bool,
245 stdout: &mut StandardStreamLock,
246) -> std::io::Result<()> {
247 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
248
249 color(stdout, Color::Blue)?;
250 write!(stdout, "{prefix}{pref}")?;
251
252 intense_color(stdout, Color::Green)?;
253 writeln!(stdout, "tokens")?;
254
255 let prefix = format!("{prefix}{pref_child}");
256 dump_value("sum", stats.tokens_sum(), &prefix, false, stdout)?;
257 dump_value("average", stats.tokens_average(), &prefix, false, stdout)?;
258 dump_value("min", stats.tokens_min(), &prefix, false, stdout)?;
259 dump_value("max", stats.tokens_max(), &prefix, true, stdout)
260}
261
262fn dump_mi(
263 stats: &mi::Stats,
264 prefix: &str,
265 last: bool,
266 stdout: &mut StandardStreamLock,
267) -> std::io::Result<()> {
268 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
269
270 color(stdout, Color::Blue)?;
271 write!(stdout, "{prefix}{pref}")?;
272
273 intense_color(stdout, Color::Green)?;
274 writeln!(stdout, "mi")?;
275
276 let prefix = format!("{prefix}{pref_child}");
277 dump_value("mi_original", stats.mi_original(), &prefix, false, stdout)?;
278 dump_value("mi_sei", stats.mi_sei(), &prefix, false, stdout)?;
279 dump_value(
280 "mi_visual_studio",
281 stats.mi_visual_studio(),
282 &prefix,
283 true,
284 stdout,
285 )
286}
287
288fn dump_nargs(
289 stats: &nargs::Stats,
290 prefix: &str,
291 last: bool,
292 stdout: &mut StandardStreamLock,
293) -> std::io::Result<()> {
294 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
295
296 color(stdout, Color::Blue)?;
297 write!(stdout, "{prefix}{pref}")?;
298
299 intense_color(stdout, Color::Green)?;
300 writeln!(stdout, "nargs")?;
301
302 let prefix = format!("{prefix}{pref_child}");
303 dump_value("functions", stats.fn_args(), &prefix, false, stdout)?;
304 dump_value("closures", stats.closure_args(), &prefix, false, stdout)?;
305 dump_value("total", stats.nargs_total(), &prefix, false, stdout)?;
306 dump_value("average", stats.nargs_average(), &prefix, true, stdout)
307}
308
309fn dump_nexits(
310 stats: &exit::Stats,
311 prefix: &str,
312 last: bool,
313 stdout: &mut StandardStreamLock,
314) -> std::io::Result<()> {
315 let pref = if last { "`- " } else { "|- " };
316
317 color(stdout, Color::Blue)?;
318 write!(stdout, "{prefix}{pref}")?;
319
320 intense_color(stdout, Color::Green)?;
321 write!(stdout, "nexits: ")?;
322
323 color(stdout, Color::White)?;
324 writeln!(stdout, "{}", stats.exit())
325}
326
327fn dump_abc(
328 stats: &abc::Stats,
329 prefix: &str,
330 last: bool,
331 stdout: &mut StandardStreamLock,
332) -> std::io::Result<()> {
333 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
334
335 color(stdout, Color::Blue)?;
336 write!(stdout, "{prefix}{pref}")?;
337
338 intense_color(stdout, Color::Green)?;
339 writeln!(stdout, "abc")?;
340
341 let prefix = format!("{prefix}{pref_child}");
342
343 dump_value(
344 "assignments",
345 stats.assignments_sum(),
346 &prefix,
347 false,
348 stdout,
349 )?;
350 dump_value("branches", stats.branches_sum(), &prefix, false, stdout)?;
351 dump_value("conditions", stats.conditions_sum(), &prefix, false, stdout)?;
352 dump_value("magnitude", stats.magnitude_sum(), &prefix, true, stdout)
353}
354
355fn dump_wmc(
356 stats: &wmc::Stats,
357 prefix: &str,
358 last: bool,
359 stdout: &mut StandardStreamLock,
360) -> std::io::Result<()> {
361 if stats.is_disabled() {
362 return Ok(());
363 }
364
365 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
366
367 color(stdout, Color::Blue)?;
368 write!(stdout, "{prefix}{pref}")?;
369
370 intense_color(stdout, Color::Green)?;
371 writeln!(stdout, "wmc")?;
372
373 let prefix = format!("{prefix}{pref_child}");
374 dump_value("classes", stats.class_wmc_sum(), &prefix, false, stdout)?;
375 dump_value(
376 "interfaces",
377 stats.interface_wmc_sum(),
378 &prefix,
379 false,
380 stdout,
381 )?;
382 dump_value("total", stats.total_wmc(), &prefix, true, stdout)
383}
384
385fn dump_npm(
386 stats: &npm::Stats,
387 prefix: &str,
388 last: bool,
389 stdout: &mut StandardStreamLock,
390) -> std::io::Result<()> {
391 if stats.is_disabled() {
392 return Ok(());
393 }
394
395 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
396
397 color(stdout, Color::Blue)?;
398 write!(stdout, "{prefix}{pref}")?;
399
400 intense_color(stdout, Color::Green)?;
401 writeln!(stdout, "npm")?;
402
403 let prefix = format!("{prefix}{pref_child}");
404 dump_value("classes", stats.class_npm_sum(), &prefix, false, stdout)?;
405 dump_value(
406 "interfaces",
407 stats.interface_npm_sum(),
408 &prefix,
409 false,
410 stdout,
411 )?;
412 dump_value("total", stats.total_npm(), &prefix, false, stdout)?;
413 dump_value("average", stats.total_coa(), &prefix, true, stdout)
414}
415
416fn dump_npa(
417 stats: &npa::Stats,
418 prefix: &str,
419 last: bool,
420 stdout: &mut StandardStreamLock,
421) -> std::io::Result<()> {
422 if stats.is_disabled() {
423 return Ok(());
424 }
425
426 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
427
428 color(stdout, Color::Blue)?;
429 write!(stdout, "{prefix}{pref}")?;
430
431 intense_color(stdout, Color::Green)?;
432 writeln!(stdout, "npa")?;
433
434 let prefix = format!("{prefix}{pref_child}");
435 dump_value("classes", stats.class_npa_sum(), &prefix, false, stdout)?;
436 dump_value(
437 "interfaces",
438 stats.interface_npa_sum(),
439 &prefix,
440 false,
441 stdout,
442 )?;
443 dump_value("total", stats.total_npa(), &prefix, false, stdout)?;
444 dump_value("average", stats.total_cda(), &prefix, true, stdout)
445}
446
447fn dump_value(
448 name: &str,
449 val: f64,
450 prefix: &str,
451 last: bool,
452 stdout: &mut StandardStreamLock,
453) -> std::io::Result<()> {
454 let pref = if last { "`- " } else { "|- " };
455
456 color(stdout, Color::Blue)?;
457 write!(stdout, "{prefix}{pref}")?;
458
459 intense_color(stdout, Color::Magenta)?;
460 write!(stdout, "{name}: ")?;
461
462 color(stdout, Color::White)?;
463 writeln!(stdout, "{val}")
464}