Skip to main content

rigsql_output/
human.rs

1use std::path::Path;
2
3use rigsql_rules::LintViolation;
4
5/// Human-readable terminal output formatter.
6pub struct HumanFormatter {
7    use_color: bool,
8}
9
10impl HumanFormatter {
11    pub fn new(use_color: bool) -> Self {
12        Self { use_color }
13    }
14
15    /// Format violations for a single file.
16    pub fn format_file(&self, path: &Path, source: &str, violations: &[LintViolation]) -> String {
17        if violations.is_empty() {
18            return String::new();
19        }
20
21        let mut out = String::new();
22
23        // File header
24        if self.use_color {
25            out.push_str(&format!("\x1b[1m{}\x1b[0m\n", path.display()));
26        } else {
27            out.push_str(&format!("{}\n", path.display()));
28        }
29
30        for v in violations {
31            let (line, col) = v.line_col(source);
32
33            if self.use_color {
34                out.push_str(&format!(
35                    "  \x1b[90mL{:>4}:{:<3}\x1b[0m | \x1b[33m{}\x1b[0m | {}\n",
36                    line, col, v.rule_code, v.message
37                ));
38            } else {
39                out.push_str(&format!(
40                    "  L{:>4}:{:<3} | {} | {}\n",
41                    line, col, v.rule_code, v.message
42                ));
43            }
44        }
45
46        out
47    }
48
49    /// Format a summary line.
50    pub fn format_summary(
51        &self,
52        total_files: usize,
53        files_with_violations: usize,
54        total_violations: usize,
55    ) -> String {
56        let status = if total_violations == 0 {
57            if self.use_color {
58                "\x1b[32mAll checks passed!\x1b[0m".to_string()
59            } else {
60                "All checks passed!".to_string()
61            }
62        } else {
63            let msg = format!(
64                "Found {} violation(s) in {} file(s) ({} file(s) scanned).",
65                total_violations, files_with_violations, total_files
66            );
67            if self.use_color {
68                format!("\x1b[31m{}\x1b[0m", msg)
69            } else {
70                msg
71            }
72        };
73
74        format!("\n{}\n", status)
75    }
76}