flatten_rust/
exclusions.rs1use crate::config::TemplateManager;
8use anyhow::Result;
9use std::collections::HashSet;
10use std::path::Path;
11
12#[derive(Debug)]
17pub struct ExclusionManager {
18 template_manager: TemplateManager,
19 enabled_templates: HashSet<String>,
20}
21
22impl ExclusionManager {
23 pub async fn new() -> Result<Self> {
39 let mut template_manager = TemplateManager::new()?;
40 template_manager.update_if_needed().await?;
41
42 Ok(Self {
43 template_manager,
44 enabled_templates: HashSet::new(),
45 })
46 }
47
48 pub async fn enable_templates_for_project(&mut self, project_path: &Path) -> Result<()> {
52 let detection_map = Self::get_detection_map();
53 for (template_key, file_indicators) in detection_map {
54 for indicator in file_indicators {
55 if project_path.join(indicator).exists() {
56 self.enabled_templates.insert(template_key.to_string());
57 break;
58 }
59 }
60 }
61 Ok(())
62 }
63
64 fn get_detection_map() -> Vec<(&'static str, Vec<&'static str>)> {
66 vec![
67 ("rust", vec!["Cargo.toml"]),
68 ("node", vec!["package.json"]),
69 ("python", vec!["requirements.txt", "pyproject.toml"]),
70 ("java", vec!["pom.xml", "build.gradle"]),
71 ("go", vec!["go.mod"]),
72 ("ruby", vec!["Gemfile"]),
73 ("php", vec!["composer.json"]),
74 ]
75 }
76
77 pub fn get_all_patterns(&self) -> Vec<String> {
79 let mut patterns = Vec::new();
80 for key in &self.enabled_templates {
81 if let Some(contents) = self.template_manager.get_template_contents(key) {
82 patterns.extend(Self::parse_ignore_patterns(contents));
83 }
84 }
85 patterns
86 }
87
88 fn parse_ignore_patterns(content: &str) -> Vec<String> {
90 content
91 .lines()
92 .map(|s| s.trim())
93 .filter(|s| !s.is_empty() && !s.starts_with('#'))
94 .map(|s| s.to_string())
95 .collect()
96 }
97
98 pub async fn get_folder_patterns(&self) -> HashSet<String> {
100 self.get_all_patterns()
101 .iter()
102 .filter_map(|p| Self::extract_folder_name(p))
103 .collect()
104 }
105
106 pub async fn get_extension_patterns(&self) -> HashSet<String> {
108 self.get_all_patterns()
109 .iter()
110 .filter_map(|p| Self::extract_extension(p))
111 .collect()
112 }
113
114 fn extract_folder_name(pattern: &str) -> Option<String> {
116 let p = pattern.trim_end_matches('/');
117 if !p.contains('*') && !p.contains('.') {
118 return Some(p.to_string());
119 }
120 None
121 }
122
123 fn extract_extension(pattern: &str) -> Option<String> {
125 if pattern.starts_with("*.") {
126 return Some(pattern.trim_start_matches("*.").to_string());
127 }
128 None
129 }
130
131 pub fn get_enabled_templates(&self) -> Vec<&str> {
133 self.enabled_templates.iter().map(|s| s.as_str()).collect()
134 }
135
136 pub fn enable_template(&mut self, template_key: String) {
138 self.enabled_templates.insert(template_key);
139 }
140
141 pub fn disable_template(&mut self, template_key: &str) {
143 self.enabled_templates.remove(template_key);
144 }
145
146 pub async fn force_update_templates(&mut self) -> Result<()> {
148 self.template_manager.force_update().await
149 }
150
151 pub async fn get_available_templates(&self) -> Vec<String> {
153 self.template_manager.get_available_templates()
154 }
155}
156
157#[cfg(test)]
158mod tests {
159 use super::*;
160
161 #[test]
162 fn test_parse_ignore_patterns() {
163 let content = "
164# Comment
165target/
166*.log
167file.txt
168 ";
169 let patterns = ExclusionManager::parse_ignore_patterns(content);
170 assert_eq!(patterns, vec!["target/", "*.log", "file.txt"]);
171 }
172
173 #[test]
174 fn test_extract_folder_name() {
175 assert_eq!(ExclusionManager::extract_folder_name("target/"), Some("target".to_string()));
176 assert_eq!(ExclusionManager::extract_folder_name("node_modules"), Some("node_modules".to_string()));
177 assert_eq!(ExclusionManager::extract_folder_name("*.log"), None);
178 assert_eq!(ExclusionManager::extract_folder_name("file.txt"), None);
179 }
180
181 #[test]
182 fn test_extract_extension() {
183 assert_eq!(ExclusionManager::extract_extension("*.log"), Some("log".to_string()));
184 assert_eq!(ExclusionManager::extract_extension("*.pyc"), Some("pyc".to_string()));
185 assert_eq!(ExclusionManager::extract_extension("target/"), None);
186 assert_eq!(ExclusionManager::extract_extension("file.txt"), None);
187 }
188}