Skip to main content

lean_ctx/core/patterns/
mix.rs

1pub fn compress(cmd: &str, output: &str) -> Option<String> {
2    let trimmed = output.trim();
3    if trimmed.is_empty() {
4        return Some("ok".to_string());
5    }
6
7    if cmd.contains("test") {
8        return Some(compress_test(trimmed));
9    }
10    if cmd.contains("deps.get") || cmd.contains("deps.compile") {
11        return Some(compress_deps(trimmed));
12    }
13    if cmd.contains("compile") || cmd.contains("build") {
14        return Some(compress_compile(trimmed));
15    }
16    if cmd.contains("format") || cmd.contains("fmt") {
17        return Some(compress_format(trimmed));
18    }
19    if cmd.contains("credo") || cmd.contains("dialyzer") {
20        return Some(compress_lint(trimmed));
21    }
22
23    Some(compact_lines(trimmed, 15))
24}
25
26fn compress_test(output: &str) -> String {
27    let summary = output
28        .lines()
29        .rev()
30        .find(|l| l.contains("test") && (l.contains("passed") || l.contains("failure")));
31
32    if let Some(s) = summary {
33        let mut result = format!("mix test: {}", s.trim());
34        let failures: Vec<&str> = output
35            .lines()
36            .filter(|l| {
37                l.trim().starts_with("1)")
38                    || l.trim().starts_with("2)")
39                    || l.trim().starts_with("3)")
40            })
41            .collect();
42        for f in failures.iter().take(5) {
43            result.push_str(&format!("\n  {}", f.trim()));
44        }
45        return result;
46    }
47    compact_lines(output, 10)
48}
49
50fn compress_deps(output: &str) -> String {
51    let mut resolved = 0u32;
52    let mut compiled = 0u32;
53
54    for line in output.lines() {
55        if line.contains("Resolving") || line.contains("resolving") {
56            resolved += 1;
57        }
58        if line.contains("Compiling") || line.contains("compiling") {
59            compiled += 1;
60        }
61    }
62
63    if resolved == 0 && compiled == 0 {
64        return compact_lines(output, 5);
65    }
66    format!("deps: {resolved} resolved, {compiled} compiled")
67}
68
69fn compress_compile(output: &str) -> String {
70    let mut compiled = 0u32;
71    let mut warnings = 0u32;
72    let mut errors = Vec::new();
73
74    for line in output.lines() {
75        let trimmed = line.trim();
76        if trimmed.starts_with("Compiling") || trimmed.starts_with("Compiled") {
77            compiled += 1;
78        }
79        if trimmed.contains("warning:") {
80            warnings += 1;
81        }
82        if trimmed.contains("error") && trimmed.contains("**") {
83            errors.push(trimmed.to_string());
84        }
85    }
86
87    if !errors.is_empty() {
88        let mut result = format!("{} errors", errors.len());
89        for e in errors.iter().take(10) {
90            result.push_str(&format!("\n  {e}"));
91        }
92        return result;
93    }
94
95    let mut result = format!("{compiled} compiled");
96    if warnings > 0 {
97        result.push_str(&format!(", {warnings} warnings"));
98    }
99    result
100}
101
102fn compress_format(output: &str) -> String {
103    let files: Vec<&str> = output.lines().filter(|l| !l.trim().is_empty()).collect();
104    if files.is_empty() {
105        return "ok (formatted)".to_string();
106    }
107    format!("{} files", files.len())
108}
109
110fn compress_lint(output: &str) -> String {
111    let issues: Vec<&str> = output
112        .lines()
113        .filter(|l| {
114            let t = l.trim();
115            t.contains("┃") || t.starts_with("warning:") || t.starts_with("error:")
116        })
117        .collect();
118
119    if issues.is_empty() {
120        if output.contains("no issues") || output.contains("Analysis finished") {
121            return "clean".to_string();
122        }
123        return compact_lines(output, 10);
124    }
125    format!(
126        "{} issues:\n{}",
127        issues.len(),
128        issues
129            .iter()
130            .take(10)
131            .map(|i| format!("  {}", i.trim()))
132            .collect::<Vec<_>>()
133            .join("\n")
134    )
135}
136
137fn compact_lines(text: &str, max: usize) -> String {
138    let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
139    if lines.len() <= max {
140        return lines.join("\n");
141    }
142    format!(
143        "{}\n... ({} more lines)",
144        lines[..max].join("\n"),
145        lines.len() - max
146    )
147}