Skip to main content

deepseek_rust_cli/tools/file/
analysis.rs

1use std::{collections::HashMap, path::Path};
2
3use anyhow::Result;
4use async_trait::async_trait;
5use serde_json::Value;
6use walkdir::WalkDir;
7
8use crate::{agent::types::UndoAction, tools::base::Tool};
9
10pub struct ProjectSummaryTool;
11#[async_trait]
12impl Tool for ProjectSummaryTool {
13    fn name(&self) -> &str {
14        "summarize_project"
15    }
16    async fn execute(
17        &self,
18        _args: &HashMap<String, Value>,
19        _undo: &mut Vec<UndoAction>,
20        _cwd: Option<&Path>,
21    ) -> Result<String> {
22        let mut extensions: HashMap<String, usize> = HashMap::new();
23        let mut total_files = 0;
24        let mut total_lines = 0;
25        let mut core_files = Vec::new();
26
27        for entry in WalkDir::new(".").into_iter().filter_map(|e| e.ok()) {
28            if entry.file_type().is_file() {
29                let path = entry.path();
30                if path.to_string_lossy().contains(".git")
31                    || path.to_string_lossy().contains("target")
32                {
33                    continue;
34                }
35
36                total_files += 1;
37                if let Some(ext) = path.extension().and_then(|e| e.to_str()) {
38                    *extensions.entry(ext.to_string()).or_insert(0) += 1;
39                }
40
41                // Check for core files
42                let name = entry.file_name().to_string_lossy();
43                if name == "Cargo.toml"
44                    || name == "package.json"
45                    || name == "main.rs"
46                    || name == "lib.rs"
47                {
48                    core_files.push(path.display().to_string());
49                }
50
51                // Sample lines
52                if let Ok(content) = std::fs::read_to_string(path) {
53                    total_lines += content.lines().count();
54                }
55            }
56        }
57
58        let mut summary = format!(
59            "Project Summary:\n- Total Files: {}\n- Total Lines: {}\n\nCore Files Found:\n",
60            total_files, total_lines
61        );
62        for f in core_files {
63            summary.push_str(&format!("  - {}\n", f));
64        }
65
66        summary.push_str("\nFile Extensions:\n");
67        let mut ext_list: Vec<_> = extensions.into_iter().collect();
68        ext_list.sort_by_key(|x| std::cmp::Reverse(x.1));
69        for (ext, count) in ext_list.into_iter().take(10) {
70            summary.push_str(&format!("  - .{}: {} files\n", ext, count));
71        }
72
73        Ok(summary)
74    }
75}
76
77pub struct ListTodoTasksTool;
78#[async_trait]
79impl Tool for ListTodoTasksTool {
80    fn name(&self) -> &str {
81        "list_todo_tasks"
82    }
83    async fn execute(
84        &self,
85        _args: &HashMap<String, Value>,
86        _undo: &mut Vec<UndoAction>,
87        _cwd: Option<&Path>,
88    ) -> Result<String> {
89        let mut tasks = Vec::new();
90        let keywords = ["TODO", "FIXME", "HACK", "BUG"];
91
92        for entry in WalkDir::new(".").into_iter().filter_map(|e| e.ok()) {
93            if entry.file_type().is_file() {
94                let path = entry.path();
95                if path.to_string_lossy().contains(".git")
96                    || path.to_string_lossy().contains("target")
97                {
98                    continue;
99                }
100
101                if let Ok(content) = std::fs::read_to_string(path) {
102                    for (i, line) in content.lines().enumerate() {
103                        for kw in &keywords {
104                            if line.contains(kw) {
105                                tasks.push(format!(
106                                    "{}:{}: {}",
107                                    path.display(),
108                                    i + 1,
109                                    line.trim()
110                                ));
111                            }
112                        }
113                    }
114                }
115            }
116        }
117
118        if tasks.is_empty() {
119            Ok("No TODO/FIXME tasks found in project.".to_string())
120        } else {
121            Ok(format!(
122                "Found {} tasks:\n\n{}",
123                tasks.len(),
124                tasks.join("\n")
125            ))
126        }
127    }
128}