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::wmc;
16
17use crate::spaces::{CodeMetrics, FuncSpace};
18
19use crate::tools::{color, intense_color};
20
21pub fn dump_root(space: &FuncSpace) -> std::io::Result<()> {
50 let stdout = StandardStream::stdout(ColorChoice::Always);
51 let mut stdout = stdout.lock();
52 dump_space(space, "", true, &mut stdout)?;
53 color(&mut stdout, Color::White)?;
54
55 Ok(())
56}
57
58fn dump_space(
59 space: &FuncSpace,
60 prefix: &str,
61 last: bool,
62 stdout: &mut StandardStreamLock,
63) -> std::io::Result<()> {
64 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
65
66 color(stdout, Color::Blue)?;
67 write!(stdout, "{prefix}{pref}")?;
68
69 intense_color(stdout, Color::Yellow)?;
70 write!(stdout, "{}: ", space.kind)?;
71
72 intense_color(stdout, Color::Cyan)?;
73 write!(stdout, "{}", space.name.as_ref().map_or("", |name| name))?;
74
75 intense_color(stdout, Color::Red)?;
76 writeln!(stdout, " (@{})", space.start_line)?;
77
78 let prefix = format!("{prefix}{pref_child}");
79 dump_metrics(&space.metrics, &prefix, space.spaces.is_empty(), stdout)?;
80
81 if let Some((last, spaces)) = space.spaces.split_last() {
82 for space in spaces {
83 dump_space(space, &prefix, false, stdout)?;
84 }
85 dump_space(last, &prefix, true, stdout)?;
86 }
87
88 Ok(())
89}
90
91fn dump_metrics(
92 metrics: &CodeMetrics,
93 prefix: &str,
94 last: bool,
95 stdout: &mut StandardStreamLock,
96) -> std::io::Result<()> {
97 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
98
99 color(stdout, Color::Blue)?;
100 write!(stdout, "{prefix}{pref}")?;
101
102 intense_color(stdout, Color::Yellow)?;
103 writeln!(stdout, "metrics")?;
104
105 let prefix = format!("{prefix}{pref_child}");
106 dump_cognitive(&metrics.cognitive, &prefix, false, stdout)?;
107 dump_cyclomatic(&metrics.cyclomatic, &prefix, false, stdout)?;
108 dump_nargs(&metrics.nargs, &prefix, false, stdout)?;
109 dump_nexits(&metrics.nexits, &prefix, false, stdout)?;
110 dump_halstead(&metrics.halstead, &prefix, false, stdout)?;
111 dump_loc(&metrics.loc, &prefix, false, stdout)?;
112 dump_nom(&metrics.nom, &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(), &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(), &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_mi(
242 stats: &mi::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, "mi")?;
254
255 let prefix = format!("{prefix}{pref_child}");
256 dump_value("mi_original", stats.mi_original(), &prefix, false, stdout)?;
257 dump_value("mi_sei", stats.mi_sei(), &prefix, false, stdout)?;
258 dump_value(
259 "mi_visual_studio",
260 stats.mi_visual_studio(),
261 &prefix,
262 true,
263 stdout,
264 )
265}
266
267fn dump_nargs(
268 stats: &nargs::Stats,
269 prefix: &str,
270 last: bool,
271 stdout: &mut StandardStreamLock,
272) -> std::io::Result<()> {
273 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
274
275 color(stdout, Color::Blue)?;
276 write!(stdout, "{prefix}{pref}")?;
277
278 intense_color(stdout, Color::Green)?;
279 writeln!(stdout, "nargs")?;
280
281 let prefix = format!("{prefix}{pref_child}");
282 dump_value("functions", stats.fn_args(), &prefix, false, stdout)?;
283 dump_value("closures", stats.closure_args(), &prefix, false, stdout)?;
284 dump_value("total", stats.nargs_total(), &prefix, false, stdout)?;
285 dump_value("average", stats.nargs_average(), &prefix, true, stdout)
286}
287
288fn dump_nexits(
289 stats: &exit::Stats,
290 prefix: &str,
291 last: bool,
292 stdout: &mut StandardStreamLock,
293) -> std::io::Result<()> {
294 let pref = if last { "`- " } else { "|- " };
295
296 color(stdout, Color::Blue)?;
297 write!(stdout, "{prefix}{pref}")?;
298
299 intense_color(stdout, Color::Green)?;
300 write!(stdout, "nexits: ")?;
301
302 color(stdout, Color::White)?;
303 writeln!(stdout, "{}", stats.exit())
304}
305
306fn dump_abc(
307 stats: &abc::Stats,
308 prefix: &str,
309 last: bool,
310 stdout: &mut StandardStreamLock,
311) -> std::io::Result<()> {
312 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
313
314 color(stdout, Color::Blue)?;
315 write!(stdout, "{prefix}{pref}")?;
316
317 intense_color(stdout, Color::Green)?;
318 writeln!(stdout, "abc")?;
319
320 let prefix = format!("{prefix}{pref_child}");
321
322 dump_value(
323 "assignments",
324 stats.assignments_sum(),
325 &prefix,
326 false,
327 stdout,
328 )?;
329 dump_value("branches", stats.branches_sum(), &prefix, false, stdout)?;
330 dump_value("conditions", stats.conditions_sum(), &prefix, false, stdout)?;
331 dump_value("magnitude", stats.magnitude_sum(), &prefix, true, stdout)
332}
333
334fn dump_wmc(
335 stats: &wmc::Stats,
336 prefix: &str,
337 last: bool,
338 stdout: &mut StandardStreamLock,
339) -> std::io::Result<()> {
340 if stats.is_disabled() {
341 return Ok(());
342 }
343
344 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
345
346 color(stdout, Color::Blue)?;
347 write!(stdout, "{prefix}{pref}")?;
348
349 intense_color(stdout, Color::Green)?;
350 writeln!(stdout, "wmc")?;
351
352 let prefix = format!("{prefix}{pref_child}");
353 dump_value("classes", stats.class_wmc_sum(), &prefix, false, stdout)?;
354 dump_value(
355 "interfaces",
356 stats.interface_wmc_sum(),
357 &prefix,
358 false,
359 stdout,
360 )?;
361 dump_value("total", stats.total_wmc(), &prefix, true, stdout)
362}
363
364fn dump_npm(
365 stats: &npm::Stats,
366 prefix: &str,
367 last: bool,
368 stdout: &mut StandardStreamLock,
369) -> std::io::Result<()> {
370 if stats.is_disabled() {
371 return Ok(());
372 }
373
374 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
375
376 color(stdout, Color::Blue)?;
377 write!(stdout, "{prefix}{pref}")?;
378
379 intense_color(stdout, Color::Green)?;
380 writeln!(stdout, "npm")?;
381
382 let prefix = format!("{prefix}{pref_child}");
383 dump_value("classes", stats.class_npm_sum(), &prefix, false, stdout)?;
384 dump_value(
385 "interfaces",
386 stats.interface_npm_sum(),
387 &prefix,
388 false,
389 stdout,
390 )?;
391 dump_value("total", stats.total_npm(), &prefix, false, stdout)?;
392 dump_value("average", stats.total_coa(), &prefix, true, stdout)
393}
394
395fn dump_npa(
396 stats: &npa::Stats,
397 prefix: &str,
398 last: bool,
399 stdout: &mut StandardStreamLock,
400) -> std::io::Result<()> {
401 if stats.is_disabled() {
402 return Ok(());
403 }
404
405 let (pref_child, pref) = if last { (" ", "`- ") } else { ("| ", "|- ") };
406
407 color(stdout, Color::Blue)?;
408 write!(stdout, "{prefix}{pref}")?;
409
410 intense_color(stdout, Color::Green)?;
411 writeln!(stdout, "npa")?;
412
413 let prefix = format!("{prefix}{pref_child}");
414 dump_value("classes", stats.class_npa_sum(), &prefix, false, stdout)?;
415 dump_value(
416 "interfaces",
417 stats.interface_npa_sum(),
418 &prefix,
419 false,
420 stdout,
421 )?;
422 dump_value("total", stats.total_npa(), &prefix, false, stdout)?;
423 dump_value("average", stats.total_cda(), &prefix, true, stdout)
424}
425
426fn dump_value(
427 name: &str,
428 val: f64,
429 prefix: &str,
430 last: bool,
431 stdout: &mut StandardStreamLock,
432) -> std::io::Result<()> {
433 let pref = if last { "`- " } else { "|- " };
434
435 color(stdout, Color::Blue)?;
436 write!(stdout, "{prefix}{pref}")?;
437
438 intense_color(stdout, Color::Magenta)?;
439 write!(stdout, "{name}: ")?;
440
441 color(stdout, Color::White)?;
442 writeln!(stdout, "{val}")
443}