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