lean_ctx/core/patterns/
swift.rs1pub 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("build") {
11 return Some(compress_build(trimmed));
12 }
13 if cmd.contains("package resolve") || cmd.contains("package update") {
14 return Some(compress_resolve(trimmed));
15 }
16
17 Some(compact_lines(trimmed, 15))
18}
19
20fn compress_test(output: &str) -> String {
21 let mut passed = 0u32;
22 let mut failed = 0u32;
23 let mut failures = Vec::new();
24 let mut time = String::new();
25
26 for line in output.lines() {
27 let trimmed = line.trim();
28 if trimmed.contains("Test Case") && trimmed.contains("passed") {
29 passed += 1;
30 } else if trimmed.contains("Test Case") && trimmed.contains("failed") {
31 failed += 1;
32 failures.push(trimmed.to_string());
33 }
34 if trimmed.starts_with("Test Suite") && trimmed.contains("Executed") {
35 time = trimmed.to_string();
36 }
37 if trimmed.contains("Executed")
38 && trimmed.contains("tests")
39 && let Some(pos) = trimmed.find("Executed")
40 {
41 time = trimmed[pos..].to_string();
42 }
43 }
44
45 if passed == 0 && failed == 0 {
46 return compact_lines(output, 10);
47 }
48
49 let mut result = format!("swift test: {passed} passed");
50 if failed > 0 {
51 result.push_str(&format!(", {failed} failed"));
52 }
53 if !time.is_empty() {
54 result.push_str(&format!("\n {time}"));
55 }
56 for f in failures.iter().take(5) {
57 result.push_str(&format!("\n FAIL: {f}"));
58 }
59 result
60}
61
62fn compress_build(output: &str) -> String {
63 let mut compiling = 0u32;
64 let mut linking = false;
65 let mut errors = Vec::new();
66 let mut warnings = 0u32;
67
68 for line in output.lines() {
69 let trimmed = line.trim();
70 if trimmed.starts_with("Compiling") || trimmed.contains('[') && trimmed.contains(']') {
71 compiling += 1;
72 }
73 if trimmed.starts_with("Linking") || trimmed.contains("Linking") {
74 linking = true;
75 }
76 if trimmed.contains("error:") {
77 errors.push(trimmed.to_string());
78 }
79 if trimmed.contains("warning:") {
80 warnings += 1;
81 }
82 }
83
84 if !errors.is_empty() {
85 let mut result = format!("{} errors", errors.len());
86 if warnings > 0 {
87 result.push_str(&format!(", {warnings} warnings"));
88 }
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!("Build ok ({compiling} compiled");
96 if linking {
97 result.push_str(", linked");
98 }
99 if warnings > 0 {
100 result.push_str(&format!(", {warnings} warnings"));
101 }
102 result.push(')');
103 result
104}
105
106fn compress_resolve(output: &str) -> String {
107 let mut fetched = 0u32;
108 let mut resolved = 0u32;
109 for line in output.lines() {
110 if line.contains("Fetching") {
111 fetched += 1;
112 }
113 if line.contains("Resolving") || line.contains("resolved") {
114 resolved += 1;
115 }
116 }
117 if fetched == 0 && resolved == 0 {
118 return compact_lines(output, 5);
119 }
120 format!("{fetched} fetched, {resolved} resolved")
121}
122
123fn compact_lines(text: &str, max: usize) -> String {
124 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
125 if lines.len() <= max {
126 return lines.join("\n");
127 }
128 format!(
129 "{}\n... ({} more lines)",
130 lines[..max].join("\n"),
131 lines.len() - max
132 )
133}