ricecoder_lsp/config/
manager.rs1use super::loader::ConfigLoader;
9use super::types::{ConfigRegistry, ConfigResult, LanguageConfig};
10use crate::code_actions::adapters::{
11 PythonCodeActionAdapter, RustCodeActionAdapter, TypeScriptCodeActionAdapter,
12};
13use crate::diagnostics::adapters::{
14 PythonDiagnosticsAdapter, RustDiagnosticsAdapter, TypeScriptDiagnosticsAdapter,
15};
16use crate::providers::{CodeActionRegistry, DiagnosticsRegistry, SemanticAnalyzerRegistry};
17use crate::semantic::adapters::{
18 FallbackAnalyzerAdapter, PythonAnalyzerAdapter, RustAnalyzerAdapter, TypeScriptAnalyzerAdapter,
19};
20use ricecoder_storage::PathResolver;
21use std::path::PathBuf;
22use std::sync::{Arc, RwLock};
23
24pub struct ConfigurationManager {
26 config_registry: Arc<RwLock<ConfigRegistry>>,
28 semantic_registry: Arc<RwLock<SemanticAnalyzerRegistry>>,
30 diagnostics_registry: Arc<RwLock<DiagnosticsRegistry>>,
32 code_action_registry: Arc<RwLock<CodeActionRegistry>>,
34}
35
36impl ConfigurationManager {
37 pub fn new() -> Self {
39 Self {
40 config_registry: Arc::new(RwLock::new(ConfigRegistry::new())),
41 semantic_registry: Arc::new(RwLock::new(SemanticAnalyzerRegistry::new())),
42 diagnostics_registry: Arc::new(RwLock::new(DiagnosticsRegistry::new())),
43 code_action_registry: Arc::new(RwLock::new(CodeActionRegistry::new())),
44 }
45 }
46
47 pub fn load_defaults(&self) -> ConfigResult<()> {
49 {
51 let mut registry = self.semantic_registry.write().unwrap();
52 registry.register(Box::new(RustAnalyzerAdapter::new()));
53 registry.register(Box::new(TypeScriptAnalyzerAdapter::new()));
54 registry.register(Box::new(PythonAnalyzerAdapter::new()));
55 registry.register(Box::new(FallbackAnalyzerAdapter::new()));
56 }
57
58 {
60 let mut registry = self.diagnostics_registry.write().unwrap();
61 registry.register(Box::new(RustDiagnosticsAdapter::new()));
62 registry.register(Box::new(TypeScriptDiagnosticsAdapter::new()));
63 registry.register(Box::new(PythonDiagnosticsAdapter::new()));
64 }
65
66 {
68 let mut registry = self.code_action_registry.write().unwrap();
69 registry.register(Box::new(RustCodeActionAdapter::new()));
70 registry.register(Box::new(TypeScriptCodeActionAdapter::new()));
71 registry.register(Box::new(PythonCodeActionAdapter::new()));
72 }
73
74 Ok(())
75 }
76
77 pub fn get_language_config_paths() -> ConfigResult<Vec<PathBuf>> {
85 let mut paths = Vec::new();
86
87 let project_path = PathResolver::resolve_project_path();
89 let project_lsp_path = project_path.join("lsp").join("languages");
90 if project_lsp_path.exists() {
91 paths.push(project_lsp_path);
92 }
93
94 if let Ok(global_path) = PathResolver::resolve_global_path() {
96 let user_lsp_path = global_path.join("lsp").join("languages");
97 if user_lsp_path.exists() {
98 paths.push(user_lsp_path);
99 }
100 }
101
102 Ok(paths)
104 }
105
106 pub fn load_from_storage(&self) -> ConfigResult<()> {
113 if let Ok(paths) = Self::get_language_config_paths() {
115 for path in paths {
116 if path.exists() {
117 self.load_from_directory(&path)?;
118 }
119 }
120 }
121
122 self.load_defaults()?;
124
125 Ok(())
126 }
127
128 pub fn load_from_directory(&self, path: &std::path::Path) -> ConfigResult<()> {
130 let registry = ConfigLoader::load_directory(path)?;
131
132 {
134 let mut config_reg = self.config_registry.write().unwrap();
135 for language in registry.languages() {
136 if let Some(config) = registry.get(language) {
137 config_reg.register(config.clone())?;
138 }
139 }
140 }
141
142 self.update_providers_from_configs()?;
144
145 Ok(())
146 }
147
148 pub fn load_config_file(&self, path: &std::path::Path) -> ConfigResult<()> {
150 let config = ConfigLoader::load(path)?;
151
152 {
154 let mut registry = self.config_registry.write().unwrap();
155 registry.register(config.clone())?;
156 }
157
158 self.update_providers_from_configs()?;
160
161 Ok(())
162 }
163
164 fn update_providers_from_configs(&self) -> ConfigResult<()> {
166 let config_reg = self.config_registry.read().unwrap();
167
168 for language in config_reg.languages() {
169 if let Some(config) = config_reg.get(language) {
170 {
172 let mut diag_reg = self.diagnostics_registry.write().unwrap();
173 match language {
174 "rust" => {
175 diag_reg.register(Box::new(RustDiagnosticsAdapter::with_config(
176 config.clone(),
177 )));
178 }
179 "typescript" => {
180 diag_reg.register(Box::new(TypeScriptDiagnosticsAdapter::with_config(
181 config.clone(),
182 )));
183 }
184 "python" => {
185 diag_reg.register(Box::new(PythonDiagnosticsAdapter::with_config(
186 config.clone(),
187 )));
188 }
189 _ => {}
190 }
191 }
192
193 {
195 let mut action_reg = self.code_action_registry.write().unwrap();
196 match language {
197 "rust" => {
198 action_reg.register(Box::new(RustCodeActionAdapter::with_config(
199 config.clone(),
200 )));
201 }
202 "typescript" => {
203 action_reg.register(Box::new(
204 TypeScriptCodeActionAdapter::with_config(config.clone()),
205 ));
206 }
207 "python" => {
208 action_reg.register(Box::new(PythonCodeActionAdapter::with_config(
209 config.clone(),
210 )));
211 }
212 _ => {}
213 }
214 }
215 }
216 }
217
218 Ok(())
219 }
220
221 pub fn config_registry(&self) -> Arc<RwLock<ConfigRegistry>> {
223 Arc::clone(&self.config_registry)
224 }
225
226 pub fn semantic_registry(&self) -> Arc<RwLock<SemanticAnalyzerRegistry>> {
228 Arc::clone(&self.semantic_registry)
229 }
230
231 pub fn diagnostics_registry(&self) -> Arc<RwLock<DiagnosticsRegistry>> {
233 Arc::clone(&self.diagnostics_registry)
234 }
235
236 pub fn code_action_registry(&self) -> Arc<RwLock<CodeActionRegistry>> {
238 Arc::clone(&self.code_action_registry)
239 }
240
241 pub fn has_language(&self, language: &str) -> bool {
243 let registry = self.config_registry.read().unwrap();
244 registry.has_language(language)
245 }
246
247 pub fn languages(&self) -> Vec<String> {
249 let registry = self.config_registry.read().unwrap();
250 registry
251 .languages()
252 .into_iter()
253 .map(|s| s.to_string())
254 .collect()
255 }
256
257 pub fn get_config(&self, language: &str) -> Option<LanguageConfig> {
259 let registry = self.config_registry.read().unwrap();
260 registry.get(language).cloned()
261 }
262}
263
264impl Default for ConfigurationManager {
265 fn default() -> Self {
266 Self::new()
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
275 fn test_configuration_manager_creation() {
276 let manager = ConfigurationManager::new();
277 assert!(manager
278 .config_registry
279 .read()
280 .unwrap()
281 .languages()
282 .is_empty());
283 }
284
285 #[test]
286 fn test_load_defaults() {
287 let manager = ConfigurationManager::new();
288 assert!(manager.load_defaults().is_ok());
289
290 let semantic_reg = manager.semantic_registry.read().unwrap();
292 assert!(semantic_reg.has_provider("rust"));
293 assert!(semantic_reg.has_provider("typescript"));
294 assert!(semantic_reg.has_provider("python"));
295 assert!(semantic_reg.has_provider("unknown"));
296 }
297
298 #[test]
299 fn test_has_language() {
300 let manager = ConfigurationManager::new();
301 manager.load_defaults().unwrap();
302
303 assert!(!manager.has_language("rust"));
305 }
306
307 #[test]
308 fn test_languages_list() {
309 let manager = ConfigurationManager::new();
310 manager.load_defaults().unwrap();
311
312 let languages = manager.languages();
313 assert!(languages.is_empty());
314 }
315}