Skip to main content

lean_ctx_patterns/
find.rs

1// SPDX-License-Identifier: Apache-2.0
2
3use std::collections::HashMap;
4
5pub fn compress(output: &str) -> Option<String> {
6    let lines: Vec<&str> = output.lines().filter(|l| !l.trim().is_empty()).collect();
7    if lines.len() < 5 {
8        return None;
9    }
10
11    let mut by_dir: HashMap<String, Vec<String>> = HashMap::new();
12    let mut total_files = 0usize;
13
14    for line in &lines {
15        let path = line.trim().strip_prefix("./").unwrap_or(line.trim());
16
17        if should_skip(path) {
18            continue;
19        }
20
21        total_files += 1;
22
23        if let Some(slash_pos) = path.rfind('/') {
24            let dir = &path[..slash_pos];
25            let file = &path[slash_pos + 1..];
26            by_dir
27                .entry(dir.to_string())
28                .or_default()
29                .push(file.to_string());
30        } else {
31            by_dir
32                .entry(".".to_string())
33                .or_default()
34                .push(path.to_string());
35        }
36    }
37
38    if total_files == 0 {
39        return None;
40    }
41
42    let mut result = format!("{total_files}F {}D:\n", by_dir.len());
43    let mut sorted_dirs: Vec<_> = by_dir.iter().collect();
44    sorted_dirs.sort_by_key(|(dir, _)| (*dir).clone());
45
46    for (dir, files) in &sorted_dirs {
47        result.push_str(&format!("\n{dir}/"));
48        let show: Vec<_> = files.iter().take(10).collect();
49        let mut line_buf = String::new();
50        for f in &show {
51            if line_buf.len() + f.len() + 1 > 60 {
52                result.push_str(&format!("\n  {line_buf}"));
53                line_buf.clear();
54            }
55            if !line_buf.is_empty() {
56                line_buf.push(' ');
57            }
58            line_buf.push_str(f);
59        }
60        if !line_buf.is_empty() {
61            result.push_str(&format!("\n  {line_buf}"));
62        }
63        if files.len() > 10 {
64            result.push_str(&format!("\n  ... +{} more", files.len() - 10));
65        }
66    }
67
68    Some(result)
69}
70
71fn should_skip(path: &str) -> bool {
72    let skip_dirs = [
73        "node_modules/",
74        ".git/",
75        "target/debug/",
76        "target/release/",
77        "__pycache__/",
78        ".svelte-kit/",
79        ".next/",
80        "dist/",
81        ".DS_Store",
82    ];
83    skip_dirs.iter().any(|d| path.contains(d))
84}