ricecoder_refactoring/providers/
lsp.rs1use crate::error::Result;
7use crate::types::{Refactoring, ValidationResult};
8use std::sync::Arc;
9
10pub trait LspProvider: Send + Sync {
15 fn is_available(&self) -> bool;
17
18 fn perform_refactoring(
20 &self,
21 code: &str,
22 language: &str,
23 refactoring: &Refactoring,
24 ) -> Result<String>;
25
26 fn validate_refactoring(
28 &self,
29 original: &str,
30 refactored: &str,
31 language: &str,
32 ) -> Result<ValidationResult>;
33
34 fn on_availability_changed(&self, callback: Box<dyn Fn(bool) + Send + Sync>);
36}
37
38#[derive(Clone)]
43pub struct LspProviderRegistry {
44 providers: Arc<std::sync::Mutex<std::collections::HashMap<String, Arc<dyn LspProvider>>>>,
45}
46
47impl LspProviderRegistry {
48 pub fn new() -> Self {
50 Self {
51 providers: Arc::new(std::sync::Mutex::new(std::collections::HashMap::new())),
52 }
53 }
54
55 pub fn register(&self, language: String, provider: Arc<dyn LspProvider>) -> Result<()> {
57 let mut providers = self.providers.lock().map_err(|_| {
58 crate::error::RefactoringError::Other(
59 "Failed to acquire lock on LSP provider registry".to_string(),
60 )
61 })?;
62 providers.insert(language, provider);
63 Ok(())
64 }
65
66 pub fn get_provider(&self, language: &str) -> Option<Arc<dyn LspProvider>> {
68 if let Ok(providers) = self.providers.lock() {
69 providers.get(language).cloned()
70 } else {
71 None
72 }
73 }
74
75 pub fn is_available(&self, language: &str) -> bool {
77 if let Some(provider) = self.get_provider(language) {
78 provider.is_available()
79 } else {
80 false
81 }
82 }
83
84 pub fn get_languages(&self) -> Result<Vec<String>> {
86 let providers = self.providers.lock().map_err(|_| {
87 crate::error::RefactoringError::Other(
88 "Failed to acquire lock on LSP provider registry".to_string(),
89 )
90 })?;
91 Ok(providers.keys().cloned().collect())
92 }
93
94 pub fn unregister(&self, language: &str) -> Result<()> {
96 let mut providers = self.providers.lock().map_err(|_| {
97 crate::error::RefactoringError::Other(
98 "Failed to acquire lock on LSP provider registry".to_string(),
99 )
100 })?;
101 providers.remove(language);
102 Ok(())
103 }
104
105 pub fn update_availability(&self, language: &str, available: bool) -> Result<()> {
107 if let Some(provider) = self.get_provider(language) {
108 if provider.is_available() != available {
109 }
112 }
113 Ok(())
114 }
115}
116
117impl Default for LspProviderRegistry {
118 fn default() -> Self {
119 Self::new()
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use super::*;
126
127 struct MockLspProvider {
128 available: std::sync::Arc<std::sync::Mutex<bool>>,
129 }
130
131 impl LspProvider for MockLspProvider {
132 fn is_available(&self) -> bool {
133 self.available.lock().map(|a| *a).unwrap_or(false)
134 }
135
136 fn perform_refactoring(
137 &self,
138 code: &str,
139 _language: &str,
140 _refactoring: &Refactoring,
141 ) -> Result<String> {
142 Ok(code.to_string())
143 }
144
145 fn validate_refactoring(
146 &self,
147 _original: &str,
148 _refactored: &str,
149 _language: &str,
150 ) -> Result<ValidationResult> {
151 Ok(ValidationResult {
152 passed: true,
153 errors: vec![],
154 warnings: vec![],
155 })
156 }
157
158 fn on_availability_changed(&self, _callback: Box<dyn Fn(bool) + Send + Sync>) {
159 }
161 }
162
163 #[test]
164 fn test_lsp_provider_registry() -> Result<()> {
165 let registry = LspProviderRegistry::new();
166
167 let available = std::sync::Arc::new(std::sync::Mutex::new(true));
168 let provider: Arc<dyn LspProvider> = Arc::new(MockLspProvider {
169 available: available.clone(),
170 });
171
172 registry.register("rust".to_string(), provider.clone())?;
173
174 assert!(registry.is_available("rust"));
175 assert!(!registry.is_available("python"));
176
177 *available.lock().unwrap() = false;
179 assert!(!registry.is_available("rust"));
180
181 Ok(())
182 }
183
184 #[test]
185 fn test_get_languages() -> Result<()> {
186 let registry = LspProviderRegistry::new();
187
188 let available = std::sync::Arc::new(std::sync::Mutex::new(true));
189 let provider: Arc<dyn LspProvider> = Arc::new(MockLspProvider {
190 available: available.clone(),
191 });
192
193 registry.register("rust".to_string(), provider.clone())?;
194 registry.register("typescript".to_string(), provider.clone())?;
195
196 let languages = registry.get_languages()?;
197 assert_eq!(languages.len(), 2);
198 assert!(languages.contains(&"rust".to_string()));
199 assert!(languages.contains(&"typescript".to_string()));
200
201 Ok(())
202 }
203
204 #[test]
205 fn test_unregister_provider() -> Result<()> {
206 let registry = LspProviderRegistry::new();
207
208 let available = std::sync::Arc::new(std::sync::Mutex::new(true));
209 let provider: Arc<dyn LspProvider> = Arc::new(MockLspProvider {
210 available: available.clone(),
211 });
212
213 registry.register("rust".to_string(), provider)?;
214 assert!(registry.is_available("rust"));
215
216 registry.unregister("rust")?;
217 assert!(!registry.is_available("rust"));
218
219 Ok(())
220 }
221}