lean_ctx_patterns/
cmake.rs1pub fn compress(cmd: &str, output: &str) -> Option<String> {
4 let trimmed = output.trim();
5 if trimmed.is_empty() {
6 return Some("ok".to_string());
7 }
8
9 if cmd.contains("--build") || cmd.contains("make") {
10 return Some(compress_build(trimmed));
11 }
12 if cmd.contains("ctest") || cmd.contains("test") {
13 return Some(compress_test(trimmed));
14 }
15
16 Some(compress_configure(trimmed))
17}
18
19fn compress_configure(output: &str) -> String {
20 let mut found_generators = Vec::new();
21 let mut found_compilers = Vec::new();
22 let mut warnings = 0u32;
23 let mut errors = Vec::new();
24
25 for line in output.lines() {
26 let trimmed = line.trim();
27 if trimmed.starts_with("-- The") && trimmed.contains("compiler") {
28 found_compilers.push(trimmed.to_string());
29 }
30 if trimmed.starts_with("-- Generating")
31 || (trimmed.starts_with("--") && trimmed.contains("generator"))
32 {
33 found_generators.push(trimmed.to_string());
34 }
35 if trimmed.contains("CMake Warning") || trimmed.starts_with("WARNING:") {
36 warnings += 1;
37 }
38 if trimmed.contains("CMake Error") || trimmed.starts_with("ERROR:") {
39 errors.push(trimmed.to_string());
40 }
41 }
42
43 if !errors.is_empty() {
44 let mut result = format!("{} errors:", errors.len());
45 for e in errors.iter().take(10) {
46 result.push_str(&format!("\n {e}"));
47 }
48 return result;
49 }
50
51 let success =
52 output.contains("Configuring done") || output.contains("Build files have been written");
53 let mut result = if success {
54 "CMake configured ok".to_string()
55 } else {
56 "CMake configure:".to_string()
57 };
58 if warnings > 0 {
59 result.push_str(&format!(" ({warnings} warnings)"));
60 }
61 if !found_compilers.is_empty() {
62 result.push_str(&format!("\n compilers: {}", found_compilers.len()));
63 }
64 result
65}
66
67fn compress_build(output: &str) -> String {
68 let lines: Vec<&str> = output.lines().collect();
69 let errors: Vec<&&str> = lines
70 .iter()
71 .filter(|l| l.contains("error:") || l.contains("Error:"))
72 .collect();
73 let warnings: Vec<&&str> = lines
74 .iter()
75 .filter(|l| l.contains("warning:") || l.contains("Warning:"))
76 .collect();
77
78 let progress_lines: Vec<&&str> = lines
79 .iter()
80 .filter(|l| l.trim().starts_with('[') && l.contains(']'))
81 .collect();
82
83 if !errors.is_empty() {
84 let mut result = format!("{} errors", errors.len());
85 if !warnings.is_empty() {
86 result.push_str(&format!(", {} warnings", warnings.len()));
87 }
88 for e in errors.iter().take(10) {
89 result.push_str(&format!("\n {}", e.trim()));
90 }
91 return result;
92 }
93
94 let mut result = format!("Build ok ({} steps", progress_lines.len().max(lines.len()));
95 if !warnings.is_empty() {
96 result.push_str(&format!(", {} warnings", warnings.len()));
97 }
98 result.push(')');
99 result
100}
101
102fn compress_test(output: &str) -> String {
103 let mut passed = 0u32;
104 let mut failed = 0u32;
105 let mut failures = Vec::new();
106
107 for line in output.lines() {
108 let trimmed = line.trim();
109 if trimmed.contains("Passed") {
110 for word in trimmed.split_whitespace() {
111 if let Ok(n) = word.parse::<u32>() {
112 passed = n;
113 break;
114 }
115 }
116 }
117 if trimmed.contains("Failed") && !trimmed.starts_with("The following") {
118 for word in trimmed.split_whitespace() {
119 if let Ok(n) = word.parse::<u32>() {
120 failed = n;
121 break;
122 }
123 }
124 }
125 if trimmed.starts_with("Failed")
126 || (trimmed.contains("***Failed") || trimmed.contains("***Exception"))
127 {
128 failures.push(trimmed.to_string());
129 }
130 }
131
132 let summary_line = output
133 .lines()
134 .rev()
135 .find(|l| l.contains("tests passed") || l.contains("% tests passed"));
136 if let Some(summary) = summary_line {
137 let mut result = format!("ctest: {}", summary.trim());
138 for f in failures.iter().take(5) {
139 result.push_str(&format!("\n {f}"));
140 }
141 return result;
142 }
143
144 if passed == 0 && failed == 0 {
145 return compact_lines(output, 10);
146 }
147
148 let mut result = format!("ctest: {passed} passed");
149 if failed > 0 {
150 result.push_str(&format!(", {failed} failed"));
151 }
152 for f in failures.iter().take(5) {
153 result.push_str(&format!("\n {f}"));
154 }
155 result
156}
157
158fn compact_lines(text: &str, max: usize) -> String {
159 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
160 if lines.len() <= max {
161 return lines.join("\n");
162 }
163 format!(
164 "{}\n{}",
165 lines[..max].join("\n"),
166 super::elision_marker(lines.len() - max)
167 )
168}