lean_ctx/core/patterns/
ls.rs1pub fn compress(output: &str) -> Option<String> {
2 let lines: Vec<&str> = output.lines().collect();
3 if lines.len() < 5 {
4 return None;
5 }
6
7 let is_long = lines.iter().any(|l| {
8 l.starts_with('-') || l.starts_with('d') || l.starts_with('l') || l.starts_with("total ")
9 });
10
11 if is_long {
12 compress_long(output)
13 } else {
14 compress_short(output)
15 }
16}
17
18fn compress_long(output: &str) -> Option<String> {
19 let mut dirs = Vec::new();
20 let mut files = Vec::new();
21
22 for line in output.lines() {
23 if line.starts_with("total ") || line.trim().is_empty() {
24 continue;
25 }
26
27 let parts: Vec<&str> = line.split_whitespace().collect();
28 if parts.len() < 9 {
29 continue;
30 }
31
32 let name = parts[8..].join(" ");
33
34 if name == "." || name == ".." {
35 continue;
36 }
37
38 if line.starts_with('d') {
39 dirs.push(format!("{name}/"));
40 } else {
41 let size = format_size(parts[4]);
42 files.push(format!("{name} {size}"));
43 }
44 }
45
46 if dirs.is_empty() && files.is_empty() {
47 return None;
48 }
49
50 let mut result = String::new();
51 for d in &dirs {
52 result.push_str(d);
53 result.push('\n');
54 }
55 for f in &files {
56 result.push_str(f);
57 result.push('\n');
58 }
59
60 result.push_str(&format!("\n{} files, {} dirs", files.len(), dirs.len()));
61
62 Some(result)
63}
64
65fn compress_short(output: &str) -> Option<String> {
66 let items: Vec<&str> = output
67 .split_whitespace()
68 .filter(|s| !s.is_empty())
69 .collect();
70
71 if items.len() < 10 {
72 return None;
73 }
74
75 let mut dirs = Vec::new();
76 let mut files = Vec::new();
77
78 for item in &items {
79 if item.ends_with('/') {
80 dirs.push(*item);
81 } else {
82 files.push(*item);
83 }
84 }
85
86 let mut result = String::new();
87 for d in &dirs {
88 result.push_str(d);
89 result.push('\n');
90 }
91
92 let mut line_buf = String::new();
93 for f in &files {
94 if line_buf.len() + f.len() + 2 > 70 {
95 result.push_str(&line_buf);
96 result.push('\n');
97 line_buf.clear();
98 }
99 if !line_buf.is_empty() {
100 line_buf.push_str(" ");
101 }
102 line_buf.push_str(f);
103 }
104 if !line_buf.is_empty() {
105 result.push_str(&line_buf);
106 result.push('\n');
107 }
108
109 result.push_str(&format!("\n{} items", dirs.len() + files.len()));
110
111 Some(result)
112}
113
114fn format_size(size_str: &str) -> String {
115 let bytes: u64 = size_str.parse().unwrap_or(0);
116 if bytes >= 1_048_576 {
117 format!("{:.1}M", bytes as f64 / 1_048_576.0)
118 } else if bytes >= 1024 {
119 format!("{:.1}K", bytes as f64 / 1024.0)
120 } else {
121 format!("{bytes}B")
122 }
123}