ricecoder_lsp/code_actions/
generic_engine.rs1use crate::providers::{CodeActionProvider, CodeActionRegistry, ProviderResult};
7use crate::types::Diagnostic;
8
9pub struct GenericCodeActionsEngine {
11 registry: CodeActionRegistry,
12}
13
14impl GenericCodeActionsEngine {
15 pub fn new() -> Self {
17 Self {
18 registry: CodeActionRegistry::new(),
19 }
20 }
21
22 pub fn register_provider(&mut self, provider: Box<dyn CodeActionProvider>) {
24 self.registry.register(provider);
25 }
26
27 pub fn registry(&self) -> &CodeActionRegistry {
29 &self.registry
30 }
31
32 pub fn registry_mut(&mut self) -> &mut CodeActionRegistry {
34 &mut self.registry
35 }
36
37 pub fn suggest_actions(
39 &self,
40 diagnostic: &Diagnostic,
41 code: &str,
42 language: &str,
43 ) -> ProviderResult<Vec<String>> {
44 if let Some(provider) = self.registry.get(language) {
45 provider.suggest_actions(diagnostic, code)
46 } else {
47 tracing::debug!(
49 "No code action provider found for language '{}', returning empty",
50 language
51 );
52 Ok(Vec::new())
53 }
54 }
55
56 pub fn apply_action(&self, code: &str, action: &str, language: &str) -> ProviderResult<String> {
58 if let Some(provider) = self.registry.get(language) {
59 provider.apply_action(code, action)
60 } else {
61 tracing::debug!(
63 "No code action provider found for language '{}', returning original code",
64 language
65 );
66 Ok(code.to_string())
67 }
68 }
69
70 pub fn has_provider(&self, language: &str) -> bool {
72 self.registry.has_provider(language)
73 }
74
75 pub fn languages(&self) -> Vec<&str> {
77 self.registry.languages()
78 }
79}
80
81impl Default for GenericCodeActionsEngine {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 struct MockCodeActionProvider;
92
93 impl CodeActionProvider for MockCodeActionProvider {
94 fn language(&self) -> &str {
95 "mock"
96 }
97
98 fn suggest_actions(
99 &self,
100 _diagnostic: &Diagnostic,
101 _code: &str,
102 ) -> ProviderResult<Vec<String>> {
103 Ok(vec!["action1".to_string()])
104 }
105
106 fn apply_action(&self, code: &str, _action: &str) -> ProviderResult<String> {
107 Ok(code.to_string())
108 }
109
110 fn config(&self) -> Option<&crate::config::LanguageConfig> {
111 None
112 }
113 }
114
115 #[test]
116 fn test_generic_code_actions_engine_with_provider() {
117 let mut engine = GenericCodeActionsEngine::new();
118 engine.register_provider(Box::new(MockCodeActionProvider));
119
120 assert!(engine.has_provider("mock"));
121 }
122
123 #[test]
124 fn test_generic_code_actions_engine_fallback() {
125 use crate::types::{DiagnosticSeverity, Position, Range};
126
127 let engine = GenericCodeActionsEngine::new();
128
129 assert!(!engine.has_provider("unknown"));
131 let diagnostic = Diagnostic::new(
132 Range::new(Position::new(0, 0), Position::new(0, 5)),
133 DiagnosticSeverity::Error,
134 "test".to_string(),
135 );
136 let result = engine.suggest_actions(&diagnostic, "test", "unknown");
137 assert!(result.is_ok());
138 assert!(result.unwrap().is_empty());
139 }
140
141 #[test]
142 fn test_generic_code_actions_engine_languages() {
143 let mut engine = GenericCodeActionsEngine::new();
144 engine.register_provider(Box::new(MockCodeActionProvider));
145
146 let languages = engine.languages();
147 assert!(languages.contains(&"mock"));
148 }
149}