lean_ctx_patterns/
helm.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("list") || cmd.contains("ls") {
10 return Some(compress_list(trimmed));
11 }
12 if cmd.contains("install") || cmd.contains("upgrade") {
13 return Some(compress_install(trimmed));
14 }
15 if cmd.contains("status") {
16 return Some(compress_status(trimmed));
17 }
18 if cmd.contains("template") || cmd.contains("dry-run") {
19 return Some(compress_template(trimmed));
20 }
21 if cmd.contains("repo") {
22 return Some(compress_repo(trimmed));
23 }
24
25 Some(compact_lines(trimmed, 15))
26}
27
28fn compress_list(output: &str) -> String {
29 let lines: Vec<&str> = output.lines().collect();
30 if lines.len() <= 1 {
31 return "no releases".to_string();
32 }
33
34 let header = lines[0];
35 let releases: Vec<&str> = lines[1..]
36 .iter()
37 .copied()
38 .filter(|l| !l.trim().is_empty())
39 .collect();
40 if releases.len() <= 15 {
41 return output.to_string();
42 }
43 format!(
44 "{header}\n{}\n... ({} more)",
45 releases[..10].join("\n"),
46 releases.len() - 10
47 )
48}
49
50fn compress_install(output: &str) -> String {
51 let mut name = String::new();
52 let mut status = String::new();
53 let mut notes_start = false;
54 let mut notes = Vec::new();
55
56 for line in output.lines() {
57 let trimmed = line.trim();
58 if trimmed.starts_with("NAME:") {
59 name = trimmed
60 .strip_prefix("NAME:")
61 .unwrap_or("")
62 .trim()
63 .to_string();
64 } else if trimmed.starts_with("STATUS:") {
65 status = trimmed
66 .strip_prefix("STATUS:")
67 .unwrap_or("")
68 .trim()
69 .to_string();
70 } else if trimmed == "NOTES:" {
71 notes_start = true;
72 } else if notes_start && !trimmed.is_empty() && notes.len() < 5 {
73 notes.push(trimmed.to_string());
74 }
75 }
76
77 let mut result = format!("{name}: {status}");
78 if !notes.is_empty() {
79 result.push_str(&format!("\nnotes: {}", notes.join(" | ")));
80 }
81 result
82}
83
84fn compress_status(output: &str) -> String {
85 let mut parts = Vec::new();
86 for line in output.lines() {
87 let trimmed = line.trim();
88 if trimmed.starts_with("NAME:")
89 || trimmed.starts_with("STATUS:")
90 || trimmed.starts_with("NAMESPACE:")
91 || trimmed.starts_with("REVISION:")
92 || trimmed.starts_with("LAST DEPLOYED:")
93 {
94 parts.push(trimmed.to_string());
95 }
96 }
97 if parts.is_empty() {
98 return compact_lines(output, 10);
99 }
100 parts.join("\n")
101}
102
103fn compress_template(output: &str) -> String {
104 let lines: Vec<&str> = output.lines().collect();
105 let yaml_docs: Vec<usize> = lines
106 .iter()
107 .enumerate()
108 .filter(|(_, l)| l.trim() == "---")
109 .map(|(i, _)| i)
110 .collect();
111
112 let mut kinds = Vec::new();
113 for line in &lines {
114 let trimmed = line.trim();
115 if trimmed.starts_with("kind:") {
116 kinds.push(
117 trimmed
118 .strip_prefix("kind:")
119 .unwrap_or("")
120 .trim()
121 .to_string(),
122 );
123 }
124 }
125
126 if kinds.is_empty() {
127 return format!("{} lines of YAML", lines.len());
128 }
129
130 let mut counts: std::collections::HashMap<&str, u32> = std::collections::HashMap::new();
131 for k in &kinds {
132 *counts.entry(k.as_str()).or_insert(0) += 1;
133 }
134 let summary: Vec<String> = counts.iter().map(|(k, v)| format!(" {k}: {v}")).collect();
135 format!(
136 "{} YAML docs ({} resources):\n{}",
137 yaml_docs.len().max(1),
138 kinds.len(),
139 summary.join("\n")
140 )
141}
142
143fn compress_repo(output: &str) -> String {
144 compact_lines(output, 10)
145}
146
147fn compact_lines(text: &str, max: usize) -> String {
148 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
149 if lines.len() <= max {
150 return lines.join("\n");
151 }
152 format!(
153 "{}\n{}",
154 lines[..max].join("\n"),
155 super::elision_marker(lines.len() - max)
156 )
157}