Skip to main content

matrixcode_core/command/handlers/
overview.rs

1//! /overview 命令处理器
2
3use std::future::Future;
4use std::pin::Pin;
5
6use crate::command::{BackendContext, Command};
7
8pub struct Overview;
9
10impl Command for Overview {
11    fn name(&self) -> &'static str {
12        "overview"
13    }
14
15    fn help(&self) -> Option<&'static str> {
16        Some("显示项目概览")
17    }
18
19    fn execute<'a>(
20        &'a self,
21        ctx: &'a mut BackendContext<'_>,
22    ) -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> {
23        Box::pin(async move {
24            // 检查项目路径
25            let Some(project_path) = ctx.project_path else {
26                let _ = ctx
27                    .event_tx
28                    .send(crate::AgentEvent::progress(
29                        "未指定项目路径".to_string(),
30                        None,
31                    ))
32                    .await;
33                return false;
34            };
35
36            // 尝试读取项目结构
37            let readme_path = project_path.join("README.md");
38            let mut info = "📂 项目概览:\n\n".to_string();
39
40            // 读取 README
41            if readme_path.exists() {
42                if let Ok(content) = tokio::fs::read_to_string(&readme_path).await {
43                    let lines: Vec<&str> = content.lines().take(20).collect();
44                    info.push_str("README:\n");
45                    info.push_str(&lines.join("\n"));
46                    info.push_str("\n\n");
47                }
48            }
49
50            // 列出目录结构
51            info.push_str("目录结构:\n");
52            if let Ok(mut entries) = tokio::fs::read_dir(project_path).await {
53                let mut dirs = Vec::new();
54                let mut files = Vec::new();
55
56                while let Ok(Some(entry)) = entries.next_entry().await {
57                    let name = entry.file_name().to_string_lossy().to_string();
58                    if name.starts_with('.') || name == "target" || name == "node_modules" {
59                        continue;
60                    }
61                    if entry.file_type().await.map(|t| t.is_dir()).unwrap_or(false) {
62                        dirs.push(name);
63                    } else {
64                        files.push(name);
65                    }
66                }
67
68                dirs.sort();
69                files.sort();
70
71                for dir in dirs.iter().take(10) {
72                    info.push_str(&format!("  📁 {}/\n", dir));
73                }
74                for file in files.iter().take(10) {
75                    info.push_str(&format!("  📄 {}\n", file));
76                }
77
78                if dirs.len() > 10 || files.len() > 10 {
79                    info.push_str(&format!(
80                        "  ... 还有 {} 个目录, {} 个文件\n",
81                        dirs.len().saturating_sub(10),
82                        files.len().saturating_sub(10)
83                    ));
84                }
85            }
86
87            let _ = ctx
88                .event_tx
89                .send(crate::AgentEvent::progress(info, None))
90                .await;
91            false
92        })
93    }
94}