lean_ctx_patterns/
bazel.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("test") {
10 return Some(compress_test(trimmed));
11 }
12 if cmd.contains("build") {
13 return Some(compress_build(trimmed));
14 }
15 if cmd.contains("query") {
16 return Some(compress_query(trimmed));
17 }
18
19 Some(compact_lines(trimmed, 15))
20}
21
22fn compress_test(output: &str) -> String {
23 let mut passed = 0u32;
24 let mut failed = 0u32;
25 let mut failures = Vec::new();
26
27 for line in output.lines() {
28 let trimmed = line.trim();
29 if trimmed.contains("PASSED") {
30 passed += 1;
31 }
32 if trimmed.contains("FAILED") {
33 failed += 1;
34 failures.push(trimmed.to_string());
35 }
36 }
37
38 let summary = output
39 .lines()
40 .find(|l| l.contains("executed") || l.contains("test(s)"));
41
42 if passed == 0 && failed == 0 {
43 if let Some(s) = summary {
44 return format!("bazel test: {}", s.trim());
45 }
46 return compact_lines(output, 10);
47 }
48
49 let mut result = format!("bazel test: {passed} passed");
50 if failed > 0 {
51 result.push_str(&format!(", {failed} failed"));
52 }
53 for f in failures.iter().take(5) {
54 result.push_str(&format!("\n {f}"));
55 }
56 result
57}
58
59fn compress_build(output: &str) -> String {
60 let mut targets = 0u32;
61 let mut errors = Vec::new();
62
63 for line in output.lines() {
64 let trimmed = line.trim();
65 if (trimmed.contains("up-to-date") || trimmed.contains("Build completed"))
66 && let Some(n) = trimmed
67 .split_whitespace()
68 .find_map(|w| w.parse::<u32>().ok())
69 {
70 targets = n;
71 }
72 if trimmed.starts_with("ERROR:") || trimmed.starts_with("error:") {
73 errors.push(trimmed.to_string());
74 }
75 }
76
77 if !errors.is_empty() {
78 let mut result = format!("{} errors:", errors.len());
79 for e in errors.iter().take(10) {
80 result.push_str(&format!("\n {e}"));
81 }
82 return result;
83 }
84
85 let info_line = output
86 .lines()
87 .rev()
88 .find(|l| l.contains("INFO: Build completed") || l.contains("up-to-date"));
89 if let Some(info) = info_line {
90 return info.trim().to_string();
91 }
92
93 format!("ok ({targets} targets)")
94}
95
96fn compress_query(output: &str) -> String {
97 let targets: Vec<&str> = output.lines().filter(|l| !l.trim().is_empty()).collect();
98 if targets.len() <= 20 {
99 return targets.join("\n");
100 }
101 format!(
102 "{} targets:\n{}\n... ({} more)",
103 targets.len(),
104 targets[..15].join("\n"),
105 targets.len() - 15
106 )
107}
108
109fn compact_lines(text: &str, max: usize) -> String {
110 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
111 if lines.len() <= max {
112 return lines.join("\n");
113 }
114 format!(
115 "{}\n{}",
116 lines[..max].join("\n"),
117 super::elision_marker(lines.len() - max)
118 )
119}