ricecoder_lsp/
refactoring.rs

1//! Refactoring integration for LSP
2//!
3//! This module integrates the refactoring engine with the LSP server,
4//! providing refactoring capabilities through LSP code actions and commands.
5
6use ricecoder_refactoring::{
7    ConfigManager, GenericRefactoringProvider, ImpactAnalyzer, ProviderRegistry, RefactoringEngine, RefactoringType,
8};
9use serde_json::Value;
10use std::sync::Arc;
11use tracing::{debug, info};
12
13/// Refactoring handler for LSP
14pub struct RefactoringHandler {
15    /// Refactoring engine
16    engine: Arc<RefactoringEngine>,
17    /// Impact analyzer
18    impact_analyzer: Arc<ImpactAnalyzer>,
19    /// Configuration manager
20    config_manager: Arc<ConfigManager>,
21    /// Refactoring enabled flag
22    enabled: bool,
23}
24
25impl RefactoringHandler {
26    /// Create a new refactoring handler
27    pub fn new() -> Self {
28        let config_manager = ConfigManager::new();
29        
30        // Create generic provider for fallback
31        let generic_provider = Arc::new(GenericRefactoringProvider::new());
32        
33        // Create provider registry with generic fallback
34        let provider_registry = ProviderRegistry::new(generic_provider);
35        
36        let engine = Arc::new(RefactoringEngine::new(config_manager, provider_registry));
37        let impact_analyzer = Arc::new(ImpactAnalyzer::new());
38
39        // Create a new config manager for the handler (since we moved the first one)
40        let config_manager = Arc::new(ConfigManager::new());
41
42        Self {
43            engine,
44            impact_analyzer,
45            config_manager,
46            enabled: true,
47        }
48    }
49
50    /// Enable or disable refactoring
51    pub fn set_enabled(&mut self, enabled: bool) {
52        self.enabled = enabled;
53        if enabled {
54            info!("Refactoring engine enabled");
55        } else {
56            info!("Refactoring engine disabled");
57        }
58    }
59
60    /// Check if refactoring is enabled
61    pub fn is_enabled(&self) -> bool {
62        self.enabled
63    }
64
65    /// Get the refactoring engine
66    pub fn engine(&self) -> Arc<RefactoringEngine> {
67        self.engine.clone()
68    }
69
70    /// Get the impact analyzer
71    pub fn impact_analyzer(&self) -> Arc<ImpactAnalyzer> {
72        self.impact_analyzer.clone()
73    }
74
75
76
77    /// Get the configuration manager
78    pub fn config_manager(&self) -> Arc<ConfigManager> {
79        self.config_manager.clone()
80    }
81
82    /// Handle refactoring request
83    pub async fn handle_refactoring_request(
84        &self,
85        params: Value,
86    ) -> Result<Value, String> {
87        if !self.enabled {
88            return Err("Refactoring engine is disabled".to_string());
89        }
90
91        debug!("Handling refactoring request: {:?}", params);
92
93        // Extract refactoring type from params
94        let refactoring_type = params
95            .get("refactoringType")
96            .and_then(|v| v.as_str())
97            .ok_or("Missing refactoringType")?;
98
99        // Extract file URI
100        let file_uri = params
101            .get("fileUri")
102            .and_then(|v| v.as_str())
103            .ok_or("Missing fileUri")?;
104
105        // Extract symbol name
106        let symbol = params
107            .get("symbol")
108            .and_then(|v| v.as_str())
109            .ok_or("Missing symbol")?;
110
111        info!(
112            "Processing refactoring: type={}, file={}, symbol={}",
113            refactoring_type, file_uri, symbol
114        );
115
116        Ok(serde_json::json!({
117            "success": true,
118            "message": format!("Refactoring {} for {} in {} queued", refactoring_type, symbol, file_uri)
119        }))
120    }
121
122    /// Get available refactoring types
123    pub fn available_refactoring_types(&self) -> Vec<&'static str> {
124        vec![
125            "Rename",
126            "Extract",
127            "Inline",
128            "Move",
129            "ChangeSignature",
130            "RemoveUnused",
131            "Simplify",
132        ]
133    }
134
135    /// Get refactoring configuration for a language
136    pub async fn get_language_config(&self, language: &str) -> Result<Value, String> {
137        debug!("Getting refactoring configuration for language: {}", language);
138
139        // Check if language is available through the provider registry
140        let provider = self.engine.provider_registry().clone().get_provider(language);
141        
142        // Verify provider can handle the language
143        let analysis = provider.analyze_refactoring("code", language, RefactoringType::Rename);
144        
145        if analysis.is_ok() {
146            info!("Refactoring provider available for {}", language);
147            Ok(serde_json::json!({
148                "language": language,
149                "available": true
150            }))
151        } else {
152            info!("No refactoring provider for {}", language);
153            Err(format!("No refactoring provider for {}", language))
154        }
155    }
156}
157
158impl Default for RefactoringHandler {
159    fn default() -> Self {
160        Self::new()
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[test]
169    fn test_refactoring_handler_creation() {
170        let handler = RefactoringHandler::new();
171        assert!(handler.is_enabled());
172    }
173
174    #[test]
175    fn test_refactoring_handler_enable_disable() {
176        let mut handler = RefactoringHandler::new();
177        assert!(handler.is_enabled());
178
179        handler.set_enabled(false);
180        assert!(!handler.is_enabled());
181
182        handler.set_enabled(true);
183        assert!(handler.is_enabled());
184    }
185
186    #[test]
187    fn test_available_refactoring_types() {
188        let handler = RefactoringHandler::new();
189        let types = handler.available_refactoring_types();
190        assert!(!types.is_empty());
191        assert!(types.contains(&"Rename"));
192        assert!(types.contains(&"Extract"));
193    }
194}