ricecoder_lsp/
providers.rs1use crate::config::LanguageConfig;
7use crate::types::{Diagnostic, Position, SemanticInfo, Symbol};
8
9#[derive(Debug, Clone, thiserror::Error)]
11pub enum ProviderError {
12 #[error("Provider not found: {0}")]
14 NotFound(String),
15
16 #[error("Provider error: {0}")]
18 Error(String),
19
20 #[error("Unsupported operation: {0}")]
22 UnsupportedOperation(String),
23}
24
25pub type ProviderResult<T> = Result<T, ProviderError>;
27
28pub trait SemanticAnalyzerProvider: Send + Sync {
30 fn language(&self) -> &str;
32
33 fn analyze(&self, code: &str) -> ProviderResult<SemanticInfo>;
35
36 fn extract_symbols(&self, code: &str) -> ProviderResult<Vec<Symbol>>;
38
39 fn get_hover_info(&self, code: &str, position: Position) -> ProviderResult<Option<String>>;
41}
42
43pub trait DiagnosticsProvider: Send + Sync {
45 fn language(&self) -> &str;
47
48 fn generate_diagnostics(&self, code: &str) -> ProviderResult<Vec<Diagnostic>>;
50
51 fn config(&self) -> Option<&LanguageConfig>;
53}
54
55pub trait CodeActionProvider: Send + Sync {
57 fn language(&self) -> &str;
59
60 fn suggest_actions(&self, diagnostic: &Diagnostic, code: &str) -> ProviderResult<Vec<String>>;
62
63 fn apply_action(&self, code: &str, action: &str) -> ProviderResult<String>;
65
66 fn config(&self) -> Option<&LanguageConfig>;
68}
69
70pub struct SemanticAnalyzerRegistry {
72 providers: std::collections::HashMap<String, Box<dyn SemanticAnalyzerProvider>>,
73}
74
75impl SemanticAnalyzerRegistry {
76 pub fn new() -> Self {
78 Self {
79 providers: std::collections::HashMap::new(),
80 }
81 }
82
83 pub fn register(&mut self, provider: Box<dyn SemanticAnalyzerProvider>) {
85 let language = provider.language().to_string();
86 self.providers.insert(language, provider);
87 }
88
89 pub fn get(&self, language: &str) -> Option<&dyn SemanticAnalyzerProvider> {
91 self.providers.get(language).map(|p| p.as_ref())
92 }
93
94 pub fn has_provider(&self, language: &str) -> bool {
96 self.providers.contains_key(language)
97 }
98
99 pub fn languages(&self) -> Vec<&str> {
101 self.providers.keys().map(|s| s.as_str()).collect()
102 }
103}
104
105impl Default for SemanticAnalyzerRegistry {
106 fn default() -> Self {
107 Self::new()
108 }
109}
110
111pub struct DiagnosticsRegistry {
113 providers: std::collections::HashMap<String, Box<dyn DiagnosticsProvider>>,
114}
115
116impl DiagnosticsRegistry {
117 pub fn new() -> Self {
119 Self {
120 providers: std::collections::HashMap::new(),
121 }
122 }
123
124 pub fn register(&mut self, provider: Box<dyn DiagnosticsProvider>) {
126 let language = provider.language().to_string();
127 self.providers.insert(language, provider);
128 }
129
130 pub fn get(&self, language: &str) -> Option<&dyn DiagnosticsProvider> {
132 self.providers.get(language).map(|p| p.as_ref())
133 }
134
135 pub fn has_provider(&self, language: &str) -> bool {
137 self.providers.contains_key(language)
138 }
139
140 pub fn languages(&self) -> Vec<&str> {
142 self.providers.keys().map(|s| s.as_str()).collect()
143 }
144}
145
146impl Default for DiagnosticsRegistry {
147 fn default() -> Self {
148 Self::new()
149 }
150}
151
152pub struct CodeActionRegistry {
154 providers: std::collections::HashMap<String, Box<dyn CodeActionProvider>>,
155}
156
157impl CodeActionRegistry {
158 pub fn new() -> Self {
160 Self {
161 providers: std::collections::HashMap::new(),
162 }
163 }
164
165 pub fn register(&mut self, provider: Box<dyn CodeActionProvider>) {
167 let language = provider.language().to_string();
168 self.providers.insert(language, provider);
169 }
170
171 pub fn get(&self, language: &str) -> Option<&dyn CodeActionProvider> {
173 self.providers.get(language).map(|p| p.as_ref())
174 }
175
176 pub fn has_provider(&self, language: &str) -> bool {
178 self.providers.contains_key(language)
179 }
180
181 pub fn languages(&self) -> Vec<&str> {
183 self.providers.keys().map(|s| s.as_str()).collect()
184 }
185}
186
187impl Default for CodeActionRegistry {
188 fn default() -> Self {
189 Self::new()
190 }
191}
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196
197 struct MockSemanticProvider;
198
199 impl SemanticAnalyzerProvider for MockSemanticProvider {
200 fn language(&self) -> &str {
201 "mock"
202 }
203
204 fn analyze(&self, _code: &str) -> ProviderResult<SemanticInfo> {
205 Ok(SemanticInfo {
206 symbols: vec![],
207 imports: vec![],
208 definitions: vec![],
209 references: vec![],
210 })
211 }
212
213 fn extract_symbols(&self, _code: &str) -> ProviderResult<Vec<Symbol>> {
214 Ok(vec![])
215 }
216
217 fn get_hover_info(
218 &self,
219 _code: &str,
220 _position: Position,
221 ) -> ProviderResult<Option<String>> {
222 Ok(None)
223 }
224 }
225
226 #[test]
227 fn test_semantic_analyzer_registry() {
228 let mut registry = SemanticAnalyzerRegistry::new();
229 let provider = Box::new(MockSemanticProvider);
230
231 registry.register(provider);
232
233 assert!(registry.has_provider("mock"));
234 assert!(registry.get("mock").is_some());
235 assert!(!registry.has_provider("unknown"));
236 }
237
238 #[test]
239 fn test_semantic_analyzer_registry_languages() {
240 let mut registry = SemanticAnalyzerRegistry::new();
241 let provider = Box::new(MockSemanticProvider);
242
243 registry.register(provider);
244
245 let languages = registry.languages();
246 assert_eq!(languages.len(), 1);
247 assert!(languages.contains(&"mock"));
248 }
249}