ricecoder_refactoring/providers/
mod.rs1pub mod lsp;
7pub mod lsp_integration;
8pub mod lsp_watcher;
9
10pub use lsp::{LspProvider, LspProviderRegistry};
11pub use lsp_integration::{LspIntegration, LspServerInfo};
12pub use lsp_watcher::{ConfigurationWatcher, LspWatcher};
13
14use crate::error::Result;
15use crate::types::{Refactoring, RefactoringType, ValidationResult};
16use std::sync::Arc;
17
18pub trait RefactoringProvider: Send + Sync {
20 fn analyze_refactoring(
22 &self,
23 code: &str,
24 language: &str,
25 refactoring_type: RefactoringType,
26 ) -> Result<RefactoringAnalysis>;
27
28 fn apply_refactoring(
30 &self,
31 code: &str,
32 language: &str,
33 refactoring: &Refactoring,
34 ) -> Result<String>;
35
36 fn validate_refactoring(
38 &self,
39 original: &str,
40 refactored: &str,
41 language: &str,
42 ) -> Result<ValidationResult>;
43}
44
45#[derive(Debug, Clone)]
47pub struct RefactoringAnalysis {
48 pub applicable: bool,
50 pub reason: Option<String>,
52 pub complexity: u8,
54}
55
56#[derive(Clone)]
64pub struct ProviderRegistry {
65 lsp_providers: Arc<LspProviderRegistry>,
66 providers: std::sync::Arc<std::sync::Mutex<std::collections::HashMap<String, Arc<dyn RefactoringProvider>>>>,
67 generic_provider: Arc<dyn RefactoringProvider>,
68}
69
70impl ProviderRegistry {
71 pub fn new(generic_provider: Arc<dyn RefactoringProvider>) -> Self {
73 Self {
74 lsp_providers: Arc::new(LspProviderRegistry::new()),
75 providers: std::sync::Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())),
76 generic_provider,
77 }
78 }
79
80 pub fn with_lsp(
82 generic_provider: Arc<dyn RefactoringProvider>,
83 lsp_providers: Arc<LspProviderRegistry>,
84 ) -> Self {
85 Self {
86 lsp_providers,
87 providers: std::sync::Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())),
88 generic_provider,
89 }
90 }
91
92 pub fn lsp_providers(&self) -> Arc<LspProviderRegistry> {
94 self.lsp_providers.clone()
95 }
96
97 pub fn register(&self, language: String, provider: Arc<dyn RefactoringProvider>) -> Result<()> {
99 let mut providers = self.providers.lock().map_err(|_| {
100 crate::error::RefactoringError::Other("Failed to acquire lock on provider registry".to_string())
101 })?;
102 providers.insert(language, provider);
103 Ok(())
104 }
105
106 pub fn get_provider(&self, language: &str) -> Arc<dyn RefactoringProvider> {
111 if self.lsp_providers.is_available(language) {
113 }
116
117 if let Ok(providers) = self.providers.lock() {
119 if let Some(provider) = providers.get(language) {
120 return provider.clone();
121 }
122 }
123
124 self.generic_provider.clone()
126 }
127
128 pub fn has_provider(&self, language: &str) -> Result<bool> {
130 if self.lsp_providers.is_available(language) {
132 return Ok(true);
133 }
134
135 let providers = self.providers.lock().map_err(|_| {
137 crate::error::RefactoringError::Other("Failed to acquire lock on provider registry".to_string())
138 })?;
139 Ok(providers.contains_key(language))
140 }
141
142 pub fn get_languages(&self) -> Result<Vec<String>> {
144 let mut languages = Vec::new();
145
146 if let Ok(lsp_langs) = self.lsp_providers.get_languages() {
148 languages.extend(lsp_langs);
149 }
150
151 let providers = self.providers.lock().map_err(|_| {
153 crate::error::RefactoringError::Other("Failed to acquire lock on provider registry".to_string())
154 })?;
155 languages.extend(providers.keys().cloned());
156
157 languages.sort();
159 languages.dedup();
160
161 Ok(languages)
162 }
163
164 pub fn register_lsp_provider(
166 &self,
167 language: String,
168 provider: Arc<dyn LspProvider>,
169 ) -> Result<()> {
170 self.lsp_providers.register(language, provider)
171 }
172
173 pub fn is_lsp_available(&self, language: &str) -> bool {
175 self.lsp_providers.is_available(language)
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 struct MockProvider;
184
185 impl RefactoringProvider for MockProvider {
186 fn analyze_refactoring(
187 &self,
188 _code: &str,
189 _language: &str,
190 _refactoring_type: RefactoringType,
191 ) -> Result<RefactoringAnalysis> {
192 Ok(RefactoringAnalysis {
193 applicable: true,
194 reason: None,
195 complexity: 5,
196 })
197 }
198
199 fn apply_refactoring(
200 &self,
201 code: &str,
202 _language: &str,
203 _refactoring: &Refactoring,
204 ) -> Result<String> {
205 Ok(code.to_string())
206 }
207
208 fn validate_refactoring(
209 &self,
210 _original: &str,
211 _refactored: &str,
212 _language: &str,
213 ) -> Result<ValidationResult> {
214 Ok(ValidationResult {
215 passed: true,
216 errors: vec![],
217 warnings: vec![],
218 })
219 }
220 }
221
222 struct MockLspProvider {
223 available: std::sync::Arc<std::sync::Mutex<bool>>,
224 }
225
226 impl LspProvider for MockLspProvider {
227 fn is_available(&self) -> bool {
228 self.available.lock().map(|a| *a).unwrap_or(false)
229 }
230
231 fn perform_refactoring(
232 &self,
233 code: &str,
234 _language: &str,
235 _refactoring: &Refactoring,
236 ) -> Result<String> {
237 Ok(code.to_string())
238 }
239
240 fn validate_refactoring(
241 &self,
242 _original: &str,
243 _refactored: &str,
244 _language: &str,
245 ) -> Result<ValidationResult> {
246 Ok(ValidationResult {
247 passed: true,
248 errors: vec![],
249 warnings: vec![],
250 })
251 }
252
253 fn on_availability_changed(&self, _callback: Box<dyn Fn(bool) + Send + Sync>) {
254 }
256 }
257
258 #[test]
259 fn test_provider_registry() -> Result<()> {
260 let generic: Arc<dyn RefactoringProvider> = Arc::new(MockProvider);
261 let registry = ProviderRegistry::new(generic.clone());
262
263 let rust_provider: Arc<dyn RefactoringProvider> = Arc::new(MockProvider);
264 registry.register("rust".to_string(), rust_provider.clone())?;
265
266 assert!(registry.has_provider("rust")?);
267 assert!(!registry.has_provider("python")?);
268
269 let _provider = registry.get_provider("rust");
270 assert!(registry.has_provider("rust")?);
272
273 let _fallback = registry.get_provider("unknown");
274 assert!(!registry.has_provider("unknown")?);
276
277 Ok(())
278 }
279
280 #[test]
281 fn test_get_languages() -> Result<()> {
282 let generic = Arc::new(MockProvider);
283 let registry = ProviderRegistry::new(generic);
284
285 registry.register("rust".to_string(), Arc::new(MockProvider))?;
286 registry.register("typescript".to_string(), Arc::new(MockProvider))?;
287
288 let languages = registry.get_languages()?;
289 assert_eq!(languages.len(), 2);
290 assert!(languages.contains(&"rust".to_string()));
291 assert!(languages.contains(&"typescript".to_string()));
292
293 Ok(())
294 }
295
296 #[test]
297 fn test_lsp_provider_registration() -> Result<()> {
298 let generic = Arc::new(MockProvider);
299 let registry = ProviderRegistry::new(generic);
300
301 let available = std::sync::Arc::new(std::sync::Mutex::new(true));
302 let lsp_provider: Arc<dyn LspProvider> = Arc::new(MockLspProvider {
303 available: available.clone(),
304 });
305
306 registry.register_lsp_provider("rust".to_string(), lsp_provider)?;
307
308 assert!(registry.is_lsp_available("rust"));
309 assert!(!registry.is_lsp_available("python"));
310
311 Ok(())
312 }
313
314 #[test]
315 fn test_provider_priority_chain() -> Result<()> {
316 let generic = Arc::new(MockProvider);
317 let registry = ProviderRegistry::new(generic);
318
319 registry.register("rust".to_string(), Arc::new(MockProvider))?;
321
322 assert!(registry.has_provider("rust")?);
324
325 let available = std::sync::Arc::new(std::sync::Mutex::new(true));
327 let lsp_provider: Arc<dyn LspProvider> = Arc::new(MockLspProvider {
328 available: available.clone(),
329 });
330 registry.register_lsp_provider("rust".to_string(), lsp_provider)?;
331
332 assert!(registry.is_lsp_available("rust"));
334
335 Ok(())
336 }
337}