ricecoder_lsp/semantic/
adapters.rs

1//! Adapter implementations for existing analyzers to implement SemanticAnalyzerProvider trait
2//!
3//! This module provides adapter wrappers that allow existing language-specific analyzers
4//! to be used as pluggable providers in the configuration-driven architecture.
5
6use super::{FallbackAnalyzer, PythonAnalyzer, RustAnalyzer, SemanticAnalyzer, TypeScriptAnalyzer};
7use crate::providers::{ProviderResult, SemanticAnalyzerProvider};
8use crate::types::{Position, SemanticInfo, Symbol};
9
10/// Adapter for Rust semantic analyzer
11pub struct RustAnalyzerAdapter {
12    analyzer: RustAnalyzer,
13}
14
15impl RustAnalyzerAdapter {
16    /// Create a new Rust analyzer adapter
17    pub fn new() -> Self {
18        Self {
19            analyzer: RustAnalyzer::new(),
20        }
21    }
22}
23
24impl Default for RustAnalyzerAdapter {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl SemanticAnalyzerProvider for RustAnalyzerAdapter {
31    fn language(&self) -> &str {
32        "rust"
33    }
34
35    fn analyze(&self, code: &str) -> ProviderResult<SemanticInfo> {
36        self.analyzer
37            .analyze(code)
38            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
39    }
40
41    fn extract_symbols(&self, code: &str) -> ProviderResult<Vec<Symbol>> {
42        self.analyzer
43            .extract_symbols(code)
44            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
45    }
46
47    fn get_hover_info(&self, code: &str, position: Position) -> ProviderResult<Option<String>> {
48        self.analyzer
49            .get_hover_info(code, position)
50            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
51    }
52}
53
54/// Adapter for TypeScript semantic analyzer
55pub struct TypeScriptAnalyzerAdapter {
56    analyzer: TypeScriptAnalyzer,
57}
58
59impl TypeScriptAnalyzerAdapter {
60    /// Create a new TypeScript analyzer adapter
61    pub fn new() -> Self {
62        Self {
63            analyzer: TypeScriptAnalyzer::new(),
64        }
65    }
66}
67
68impl Default for TypeScriptAnalyzerAdapter {
69    fn default() -> Self {
70        Self::new()
71    }
72}
73
74impl SemanticAnalyzerProvider for TypeScriptAnalyzerAdapter {
75    fn language(&self) -> &str {
76        "typescript"
77    }
78
79    fn analyze(&self, code: &str) -> ProviderResult<SemanticInfo> {
80        self.analyzer
81            .analyze(code)
82            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
83    }
84
85    fn extract_symbols(&self, code: &str) -> ProviderResult<Vec<Symbol>> {
86        self.analyzer
87            .extract_symbols(code)
88            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
89    }
90
91    fn get_hover_info(&self, code: &str, position: Position) -> ProviderResult<Option<String>> {
92        self.analyzer
93            .get_hover_info(code, position)
94            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
95    }
96}
97
98/// Adapter for Python semantic analyzer
99pub struct PythonAnalyzerAdapter {
100    analyzer: PythonAnalyzer,
101}
102
103impl PythonAnalyzerAdapter {
104    /// Create a new Python analyzer adapter
105    pub fn new() -> Self {
106        Self {
107            analyzer: PythonAnalyzer::new(),
108        }
109    }
110}
111
112impl Default for PythonAnalyzerAdapter {
113    fn default() -> Self {
114        Self::new()
115    }
116}
117
118impl SemanticAnalyzerProvider for PythonAnalyzerAdapter {
119    fn language(&self) -> &str {
120        "python"
121    }
122
123    fn analyze(&self, code: &str) -> ProviderResult<SemanticInfo> {
124        self.analyzer
125            .analyze(code)
126            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
127    }
128
129    fn extract_symbols(&self, code: &str) -> ProviderResult<Vec<Symbol>> {
130        self.analyzer
131            .extract_symbols(code)
132            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
133    }
134
135    fn get_hover_info(&self, code: &str, position: Position) -> ProviderResult<Option<String>> {
136        self.analyzer
137            .get_hover_info(code, position)
138            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
139    }
140}
141
142/// Adapter for fallback semantic analyzer
143pub struct FallbackAnalyzerAdapter {
144    analyzer: FallbackAnalyzer,
145}
146
147impl FallbackAnalyzerAdapter {
148    /// Create a new fallback analyzer adapter
149    pub fn new() -> Self {
150        Self {
151            analyzer: FallbackAnalyzer::new(),
152        }
153    }
154}
155
156impl Default for FallbackAnalyzerAdapter {
157    fn default() -> Self {
158        Self::new()
159    }
160}
161
162impl SemanticAnalyzerProvider for FallbackAnalyzerAdapter {
163    fn language(&self) -> &str {
164        "unknown"
165    }
166
167    fn analyze(&self, code: &str) -> ProviderResult<SemanticInfo> {
168        self.analyzer
169            .analyze(code)
170            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
171    }
172
173    fn extract_symbols(&self, code: &str) -> ProviderResult<Vec<Symbol>> {
174        self.analyzer
175            .extract_symbols(code)
176            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
177    }
178
179    fn get_hover_info(&self, code: &str, position: Position) -> ProviderResult<Option<String>> {
180        self.analyzer
181            .get_hover_info(code, position)
182            .map_err(|e| crate::providers::ProviderError::Error(e.to_string()))
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    #[test]
191    fn test_rust_adapter_language() {
192        let adapter = RustAnalyzerAdapter::new();
193        assert_eq!(adapter.language(), "rust");
194    }
195
196    #[test]
197    fn test_typescript_adapter_language() {
198        let adapter = TypeScriptAnalyzerAdapter::new();
199        assert_eq!(adapter.language(), "typescript");
200    }
201
202    #[test]
203    fn test_python_adapter_language() {
204        let adapter = PythonAnalyzerAdapter::new();
205        assert_eq!(adapter.language(), "python");
206    }
207
208    #[test]
209    fn test_fallback_adapter_language() {
210        let adapter = FallbackAnalyzerAdapter::new();
211        assert_eq!(adapter.language(), "unknown");
212    }
213}