Skip to main content

arborist_cli/output/
table.rs

1use std::io::{self, IsTerminal, Write};
2
3use arborist::FileReport;
4use comfy_table::{ContentArrangement, Table};
5
6use crate::analysis::FlatFunction;
7use crate::cli::AnalyzeArgs;
8use crate::error::ArboristError;
9
10pub fn write_reports(reports: &[FileReport], args: &AnalyzeArgs) -> Result<(), ArboristError> {
11    let stdout = io::stdout();
12    let mut out = stdout.lock();
13    let is_tty = stdout.is_terminal();
14
15    for (i, report) in reports.iter().enumerate() {
16        if i > 0 {
17            writeln!(out)?;
18        }
19
20        writeln!(
21            out,
22            "{} ({}) \u{2014} {} function{}, {} SLOC",
23            report.path,
24            report.language,
25            report.functions.len(),
26            if report.functions.len() == 1 { "" } else { "s" },
27            report.file_sloc,
28        )?;
29
30        if report.functions.is_empty() {
31            writeln!(out)?;
32            continue;
33        }
34
35        let mut table = Table::new();
36        table.set_content_arrangement(ContentArrangement::Dynamic);
37
38        if !is_tty {
39            table.load_preset(comfy_table::presets::NOTHING);
40        }
41
42        table.set_header(vec!["Function", "Lines", "Cognitive", "Cyclomatic", "SLOC"]);
43
44        for func in &report.functions {
45            let cognitive_str = if let Some(threshold) = args.threshold {
46                if func.cognitive > threshold {
47                    if is_tty {
48                        format!("{} \u{26a0}", func.cognitive)
49                    } else {
50                        format!("{} !", func.cognitive)
51                    }
52                } else {
53                    func.cognitive.to_string()
54                }
55            } else {
56                func.cognitive.to_string()
57            };
58
59            table.add_row(vec![
60                func.name.clone(),
61                format!("{}-{}", func.start_line, func.end_line),
62                cognitive_str,
63                func.cyclomatic.to_string(),
64                func.sloc.to_string(),
65            ]);
66        }
67
68        writeln!(out, "{table}")?;
69    }
70
71    Ok(())
72}
73
74pub fn write_flat(flat: &[FlatFunction], args: &AnalyzeArgs) -> Result<(), ArboristError> {
75    let stdout = io::stdout();
76    let mut out = stdout.lock();
77    let is_tty = stdout.is_terminal();
78
79    let mut table = Table::new();
80    table.set_content_arrangement(ContentArrangement::Dynamic);
81
82    if !is_tty {
83        table.load_preset(comfy_table::presets::NOTHING);
84    }
85
86    table.set_header(vec!["Function", "File", "Cognitive", "Cyclomatic", "SLOC"]);
87
88    for func in flat {
89        let cognitive_str = if let Some(threshold) = args.threshold {
90            if func.cognitive > threshold {
91                if is_tty {
92                    format!("{} \u{26a0}", func.cognitive)
93                } else {
94                    format!("{} !", func.cognitive)
95                }
96            } else {
97                func.cognitive.to_string()
98            }
99        } else {
100            func.cognitive.to_string()
101        };
102
103        table.add_row(vec![
104            func.name.clone(),
105            func.file_path.clone(),
106            cognitive_str,
107            func.cyclomatic.to_string(),
108            func.sloc.to_string(),
109        ]);
110    }
111
112    writeln!(out, "{table}")?;
113
114    Ok(())
115}