Relocate and refactor quickfix code into its own module
We're going to have more quickfixes, to it's best not to overload the 'server' module. Plus, there's a lot of boilerplate around the quickfixes so we might want to factor it out.
This commit is contained in:
		
							parent
							
								
									763516eb96
								
							
						
					
					
						commit
						e48ac6b592
					
				|  | @ -8,6 +8,7 @@ mod cast; | ||||||
| mod edits; | mod edits; | ||||||
| pub mod error; | pub mod error; | ||||||
| mod line_numbers; | mod line_numbers; | ||||||
|  | mod quickfix; | ||||||
| pub mod server; | pub mod server; | ||||||
| mod utils; | mod utils; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,66 @@ | ||||||
|  | use crate::{edits, server::lsp_project::LspProject}; | ||||||
|  | use std::collections::HashMap; | ||||||
|  | 
 | ||||||
|  | const UNKNOWN_VARIABLE: &str = "aiken::check::unknown::variable"; | ||||||
|  | 
 | ||||||
|  | const UNKNOWN_MODULE: &str = "aiken::check::unknown::module"; | ||||||
|  | 
 | ||||||
|  | /// Errors for which we can provide quickfixes
 | ||||||
|  | pub enum Quickfix { | ||||||
|  |     UnknownVariable, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn match_code(diagnostic: &lsp_types::Diagnostic, expected: &str) -> bool { | ||||||
|  |     diagnostic.code == Some(lsp_types::NumberOrString::String(expected.to_string())) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn assert(diagnostic: &lsp_types::Diagnostic) -> Option<Quickfix> { | ||||||
|  |     let is_error = diagnostic.severity == Some(lsp_types::DiagnosticSeverity::ERROR); | ||||||
|  | 
 | ||||||
|  |     if is_error && match_code(diagnostic, UNKNOWN_VARIABLE) { | ||||||
|  |         return Some(Quickfix::UnknownVariable); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if is_error && match_code(diagnostic, UNKNOWN_MODULE) { | ||||||
|  |         todo!() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     None | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn unknown_variable( | ||||||
|  |     compiler: &LspProject, | ||||||
|  |     text_document: &lsp_types::TextDocumentIdentifier, | ||||||
|  |     diagnostic: &lsp_types::Diagnostic, | ||||||
|  | ) -> Vec<lsp_types::CodeAction> { | ||||||
|  |     let mut actions = Vec::new(); | ||||||
|  | 
 | ||||||
|  |     if let Some(parsed_document) = edits::parse_document(text_document) { | ||||||
|  |         if let Some(serde_json::Value::String(ref var_name)) = diagnostic.data { | ||||||
|  |             for module in compiler.project.modules() { | ||||||
|  |                 let mut changes = HashMap::new(); | ||||||
|  |                 if module.ast.has_definition(var_name) { | ||||||
|  |                     if let Some((title, edit)) = parsed_document.import(&module, Some(var_name)) { | ||||||
|  |                         changes.insert(text_document.uri.clone(), vec![edit]); | ||||||
|  |                         actions.push(lsp_types::CodeAction { | ||||||
|  |                             title, | ||||||
|  |                             kind: Some(lsp_types::CodeActionKind::QUICKFIX), | ||||||
|  |                             diagnostics: Some(vec![diagnostic.clone()]), | ||||||
|  |                             is_preferred: Some(true), | ||||||
|  |                             disabled: None, | ||||||
|  |                             data: None, | ||||||
|  |                             command: None, | ||||||
|  |                             edit: Some(lsp_types::WorkspaceEdit { | ||||||
|  |                                 changes: Some(changes), | ||||||
|  |                                 document_changes: None, | ||||||
|  |                                 change_annotations: None, | ||||||
|  |                             }), | ||||||
|  |                         }); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     actions | ||||||
|  | } | ||||||
|  | @ -33,9 +33,9 @@ use miette::Diagnostic; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     cast::{cast_notification, cast_request}, |     cast::{cast_notification, cast_request}, | ||||||
|     edits, |  | ||||||
|     error::Error as ServerError, |     error::Error as ServerError, | ||||||
|     line_numbers::LineNumbers, |     line_numbers::LineNumbers, | ||||||
|  |     quickfix::{self, Quickfix}, | ||||||
|     utils::{ |     utils::{ | ||||||
|         path_to_uri, span_to_lsp_range, text_edit_replace, uri_to_module_name, |         path_to_uri, span_to_lsp_range, text_edit_replace, uri_to_module_name, | ||||||
|         COMPILING_PROGRESS_TOKEN, CREATE_COMPILING_PROGRESS_TOKEN, |         COMPILING_PROGRESS_TOKEN, CREATE_COMPILING_PROGRESS_TOKEN, | ||||||
|  | @ -44,11 +44,9 @@ use crate::{ | ||||||
| 
 | 
 | ||||||
| use self::lsp_project::LspProject; | use self::lsp_project::LspProject; | ||||||
| 
 | 
 | ||||||
| mod lsp_project; | pub mod lsp_project; | ||||||
| pub mod telemetry; | pub mod telemetry; | ||||||
| 
 | 
 | ||||||
| const UNKNOWN_VARIABLE: &str = "aiken::check::unknown::variable"; |  | ||||||
| 
 |  | ||||||
| #[allow(dead_code)] | #[allow(dead_code)] | ||||||
| pub struct Server { | pub struct Server { | ||||||
|     // Project root directory
 |     // Project root directory
 | ||||||
|  | @ -331,45 +329,32 @@ impl Server { | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             CodeActionRequest::METHOD => { |             CodeActionRequest::METHOD => { | ||||||
|                 let params = |                 let mut actions = Vec::new(); | ||||||
|                     cast_request::<CodeActionRequest>(request).expect("cast code action request"); |  | ||||||
| 
 | 
 | ||||||
|                 // Identify any diagnostic which refers to an unknown variable. In which case, we
 |                 if let Some(ref compiler) = self.compiler { | ||||||
|                 // might want to provide some imports suggestion.
 |                     let params = cast_request::<CodeActionRequest>(request) | ||||||
|                 let unknown_variables = params |                         .expect("cast code action request"); | ||||||
|                     .context |  | ||||||
|                     .diagnostics |  | ||||||
|                     .into_iter() |  | ||||||
|                     .filter(|diagnostic| { |  | ||||||
|                         let is_error = |  | ||||||
|                             diagnostic.severity == Some(lsp_types::DiagnosticSeverity::ERROR); |  | ||||||
|                         let is_unknown_variable = diagnostic.code |  | ||||||
|                             == Some(lsp_types::NumberOrString::String( |  | ||||||
|                                 UNKNOWN_VARIABLE.to_string(), |  | ||||||
|                             )); |  | ||||||
| 
 | 
 | ||||||
|                         is_error && is_unknown_variable |                     for diagnostic in params.context.diagnostics.iter() { | ||||||
|                     }) |                         match quickfix::assert(diagnostic) { | ||||||
|                     .collect::<Vec<lsp_types::Diagnostic>>(); |                             Some(Quickfix::UnknownVariable) => { | ||||||
| 
 |                                 let quickfixes = quickfix::unknown_variable( | ||||||
|                 match unknown_variables.first() { |                                     compiler, | ||||||
|                     Some(diagnostic) => Ok(lsp_server::Response { |                                     ¶ms.text_document, | ||||||
|                         id, |                                     diagnostic, | ||||||
|                         error: None, |                                 ); | ||||||
|                         result: Some(serde_json::to_value( |                                 actions.extend(quickfixes); | ||||||
|                             self.quickfix_unknown_variable( |                             } | ||||||
|                                 params.text_document, |                             None => (), | ||||||
|                                 diagnostic.to_owned(), |                         } | ||||||
|                             ) |                     } | ||||||
|                             .unwrap_or(vec![]), |  | ||||||
|                         )?), |  | ||||||
|                     }), |  | ||||||
|                     None => Ok(lsp_server::Response { |  | ||||||
|                         id, |  | ||||||
|                         error: None, |  | ||||||
|                         result: Some(serde_json::Value::Null), |  | ||||||
|                     }), |  | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 Ok(lsp_server::Response { | ||||||
|  |                     id, | ||||||
|  |                     error: None, | ||||||
|  |                     result: Some(serde_json::to_value(actions)?), | ||||||
|  |                 }) | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             unsupported => Err(ServerError::UnsupportedLspRequest { |             unsupported => Err(ServerError::UnsupportedLspRequest { | ||||||
|  | @ -403,46 +388,6 @@ impl Server { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn quickfix_unknown_variable( |  | ||||||
|         &self, |  | ||||||
|         text_document: lsp_types::TextDocumentIdentifier, |  | ||||||
|         diagnostic: lsp_types::Diagnostic, |  | ||||||
|     ) -> Option<Vec<lsp_types::CodeAction>> { |  | ||||||
|         let compiler = self.compiler.as_ref()?; |  | ||||||
| 
 |  | ||||||
|         let parsed_document = edits::parse_document(&text_document)?; |  | ||||||
| 
 |  | ||||||
|         let mut actions = Vec::new(); |  | ||||||
| 
 |  | ||||||
|         if let Some(serde_json::Value::String(ref var_name)) = diagnostic.data { |  | ||||||
|             for module in compiler.project.modules() { |  | ||||||
|                 let mut changes = HashMap::new(); |  | ||||||
| 
 |  | ||||||
|                 if module.ast.has_definition(var_name) { |  | ||||||
|                     if let Some((title, edit)) = parsed_document.import(&module, Some(var_name)) { |  | ||||||
|                         changes.insert(text_document.uri.clone(), vec![edit]); |  | ||||||
|                         actions.push(lsp_types::CodeAction { |  | ||||||
|                             title, |  | ||||||
|                             kind: Some(lsp_types::CodeActionKind::QUICKFIX), |  | ||||||
|                             diagnostics: Some(vec![diagnostic.clone()]), |  | ||||||
|                             is_preferred: Some(true), |  | ||||||
|                             disabled: None, |  | ||||||
|                             data: None, |  | ||||||
|                             command: None, |  | ||||||
|                             edit: Some(lsp_types::WorkspaceEdit { |  | ||||||
|                                 changes: Some(changes), |  | ||||||
|                                 document_changes: None, |  | ||||||
|                                 change_annotations: None, |  | ||||||
|                             }), |  | ||||||
|                         }); |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         Some(actions) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn completion_for_import(&self) -> Option<Vec<lsp_types::CompletionItem>> { |     fn completion_for_import(&self) -> Option<Vec<lsp_types::CompletionItem>> { | ||||||
|         let compiler = self.compiler.as_ref()?; |         let compiler = self.compiler.as_ref()?; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	 KtorZ
						KtorZ