1use std::path::Path;
2
3use rigsql_rules::LintViolation;
4
5pub 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 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 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 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}