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::{Command, BackendContext};
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>(&'a self, ctx: &'a mut BackendContext<'_>) 
20        -> Pin<Box<dyn Future<Output = bool> + Send + 'a>> 
21    {
22        Box::pin(async move {
23            // 检查项目路径
24            let Some(project_path) = ctx.project_path else {
25                let _ = ctx.event_tx.send(crate::AgentEvent::progress(
26                    "未指定项目路径".to_string(),
27                    None,
28                )).await;
29                return false;
30            };
31
32            // 尝试读取项目结构
33            let readme_path = project_path.join("README.md");
34            let mut info = "📂 项目概览:\n\n".to_string();
35            
36            // 读取 README
37            if readme_path.exists() {
38                if let Ok(content) = tokio::fs::read_to_string(&readme_path).await {
39                    let lines: Vec<&str> = content.lines().take(20).collect();
40                    info.push_str("README:\n");
41                    info.push_str(&lines.join("\n"));
42                    info.push_str("\n\n");
43                }
44            }
45
46            // 列出目录结构
47            info.push_str("目录结构:\n");
48            if let Ok(mut entries) = tokio::fs::read_dir(project_path).await {
49                let mut dirs = Vec::new();
50                let mut files = Vec::new();
51                
52                while let Ok(Some(entry)) = entries.next_entry().await {
53                    let name = entry.file_name().to_string_lossy().to_string();
54                    if name.starts_with('.') || name == "target" || name == "node_modules" {
55                        continue;
56                    }
57                    if entry.file_type().await.map(|t| t.is_dir()).unwrap_or(false) {
58                        dirs.push(name);
59                    } else {
60                        files.push(name);
61                    }
62                }
63                
64                dirs.sort();
65                files.sort();
66                
67                for dir in dirs.iter().take(10) {
68                    info.push_str(&format!("  📁 {}/\n", dir));
69                }
70                for file in files.iter().take(10) {
71                    info.push_str(&format!("  📄 {}\n", file));
72                }
73                
74                if dirs.len() > 10 || files.len() > 10 {
75                    info.push_str(&format!("  ... 还有 {} 个目录, {} 个文件\n", 
76                        dirs.len().saturating_sub(10),
77                        files.len().saturating_sub(10)));
78                }
79            }
80
81            let _ = ctx.event_tx.send(crate::AgentEvent::progress(info, None)).await;
82            false
83        })
84    }
85}