Skip to main content

lean_ctx/tools/
ctx_heatmap.rs

1use crate::core::gain::GainEngine;
2use crate::core::heatmap;
3
4pub fn handle(action: &str, _path: Option<&str>) -> String {
5    let engine = GainEngine::load();
6
7    match action {
8        "status" => heatmap::format_heatmap_status(&engine.heatmap, 20),
9        "directory" | "dirs" => heatmap::format_directory_summary(&engine.heatmap),
10        "cold" => {
11            let all = collect_project_files(_path);
12            let cold = engine.heatmap.cold_files(&all, 20);
13            if cold.is_empty() {
14                "No cold files found (all files have been accessed).".to_string()
15            } else {
16                let mut lines = vec![format!(
17                    "Cold files (never accessed, {} total):",
18                    cold.len()
19                )];
20                for f in &cold {
21                    lines.push(format!("  {f}"));
22                }
23                lines.join("\n")
24            }
25        }
26        "json" => {
27            serde_json::to_string_pretty(&engine.heatmap).unwrap_or_else(|_| "{}".to_string())
28        }
29        _ => heatmap::format_heatmap_status(&engine.heatmap, 20),
30    }
31}
32
33fn collect_project_files(path: Option<&str>) -> Vec<String> {
34    let root = path.unwrap_or(".");
35    let mut files = Vec::new();
36    let walker = walkdir::WalkDir::new(root)
37        .max_depth(5)
38        .into_iter()
39        .filter_entry(|e| {
40            let name = e.file_name().to_string_lossy();
41            !name.starts_with('.')
42                && name != "node_modules"
43                && name != "target"
44                && name != "dist"
45                && name != "__pycache__"
46                && name != ".git"
47        });
48    for entry in walker.flatten() {
49        if entry.file_type().is_file() {
50            if let Some(ext) = entry.path().extension().and_then(|e| e.to_str()) {
51                if is_source_ext(ext) {
52                    files.push(entry.path().to_string_lossy().to_string());
53                }
54            }
55        }
56    }
57    files
58}
59
60fn is_source_ext(ext: &str) -> bool {
61    matches!(
62        ext,
63        "rs" | "ts"
64            | "tsx"
65            | "js"
66            | "jsx"
67            | "py"
68            | "go"
69            | "java"
70            | "c"
71            | "cpp"
72            | "h"
73            | "rb"
74            | "cs"
75            | "kt"
76            | "swift"
77            | "php"
78            | "svelte"
79            | "vue"
80    )
81}