1use crate::markdown_storage::{ProjectData, ProjectStorage};
7use anyhow::{Context, Result};
8use std::path::{Path, PathBuf};
9
10#[derive(Clone)]
12pub struct SimpleProjectManager {
13 storage: ProjectStorage,
15 workspace_root: PathBuf,
17}
18
19impl SimpleProjectManager {
20 pub fn new(workspace_root: PathBuf) -> Self {
22 let storage_dir = workspace_root.join(".vtcode").join("projects");
23 let storage = ProjectStorage::new(storage_dir);
24
25 Self {
26 storage,
27 workspace_root,
28 }
29 }
30
31 pub fn init(&self) -> Result<()> {
33 self.storage.init()
34 }
35
36 pub fn create_project(&self, name: &str, description: Option<&str>) -> Result<()> {
38 let mut project = ProjectData::new(name);
39 project.description = description.map(|s| s.to_string());
40
41 self.storage.save_project(&project)?;
42 Ok(())
43 }
44
45 pub fn load_project(&self, name: &str) -> Result<ProjectData> {
47 self.storage.load_project(name)
48 }
49
50 pub fn list_projects(&self) -> Result<Vec<String>> {
52 self.storage.list_projects()
53 }
54
55 pub fn delete_project(&self, name: &str) -> Result<()> {
57 self.storage.delete_project(name)
58 }
59
60 pub fn update_project(&self, project: &ProjectData) -> Result<()> {
62 self.storage.save_project(project)
63 }
64
65 pub fn project_data_dir(&self, project_name: &str) -> PathBuf {
67 self.workspace_root
68 .join(".vtcode")
69 .join("projects")
70 .join(project_name)
71 }
72
73 pub fn config_dir(&self, project_name: &str) -> PathBuf {
75 self.project_data_dir(project_name).join("config")
76 }
77
78 pub fn cache_dir(&self, project_name: &str) -> PathBuf {
80 self.project_data_dir(project_name).join("cache")
81 }
82
83 pub fn workspace_root(&self) -> &Path {
85 &self.workspace_root
86 }
87
88 pub fn project_exists(&self, name: &str) -> bool {
90 self.storage
91 .list_projects()
92 .map(|projects| projects.contains(&name.to_string()))
93 .unwrap_or(false)
94 }
95
96 pub fn get_project_info(&self, name: &str) -> Result<String> {
98 let project = self.load_project(name)?;
99
100 let mut info = format!("Project: {}\n", project.name);
101 if let Some(desc) = &project.description {
102 info.push_str(&format!("Description: {}\n", desc));
103 }
104 info.push_str(&format!("Version: {}\n", project.version));
105 info.push_str(&format!("Tags: {}\n", project.tags.join(", ")));
106
107 if !project.metadata.is_empty() {
108 info.push_str("\nMetadata:\n");
109 for (key, value) in &project.metadata {
110 info.push_str(&format!(" {}: {}\n", key, value));
111 }
112 }
113
114 Ok(info)
115 }
116
117 pub fn identify_current_project(&self) -> Result<String> {
119 let project_file = self.workspace_root.join(".vtcode-project");
121 if project_file.exists() {
122 let content = std::fs::read_to_string(&project_file)?;
123 return Ok(content.trim().to_string());
124 }
125
126 self.workspace_root
128 .file_name()
129 .and_then(|name| name.to_str())
130 .map(|name| name.to_string())
131 .ok_or_else(|| anyhow::anyhow!("Could not determine project name from directory"))
132 }
133
134 pub fn set_current_project(&self, name: &str) -> Result<()> {
136 let project_file = self.workspace_root.join(".vtcode-project");
137 std::fs::write(project_file, name)?;
138 Ok(())
139 }
140}
141
142pub struct SimpleCache {
144 cache_dir: PathBuf,
145}
146
147impl SimpleCache {
148 pub fn new(cache_dir: PathBuf) -> Self {
150 Self { cache_dir }
151 }
152
153 pub fn init(&self) -> Result<()> {
155 std::fs::create_dir_all(&self.cache_dir)?;
156 Ok(())
157 }
158
159 pub fn store(&self, key: &str, data: &str) -> Result<()> {
161 let file_path = self.cache_dir.join(format!("{}.txt", key));
162 std::fs::write(file_path, data)?;
163 Ok(())
164 }
165
166 pub fn load(&self, key: &str) -> Result<String> {
168 let file_path = self.cache_dir.join(format!("{}.txt", key));
169 std::fs::read_to_string(file_path).with_context(|| format!("Cache key '{}' not found", key))
170 }
171
172 pub fn exists(&self, key: &str) -> bool {
174 let file_path = self.cache_dir.join(format!("{}.txt", key));
175 file_path.exists()
176 }
177
178 pub fn clear(&self) -> Result<()> {
180 for entry in std::fs::read_dir(&self.cache_dir)? {
181 let entry = entry?;
182 if entry.path().is_file() {
183 std::fs::remove_file(entry.path())?;
184 }
185 }
186 Ok(())
187 }
188
189 pub fn list(&self) -> Result<Vec<String>> {
191 let mut entries = Vec::new();
192 for entry in std::fs::read_dir(&self.cache_dir)? {
193 let entry = entry?;
194 if let Some(file_name) = entry.path().file_stem() {
195 if let Some(name) = file_name.to_str() {
196 entries.push(name.to_string());
197 }
198 }
199 }
200 Ok(entries)
201 }
202}