From 766a853b487e27f8a68bc38090421096b2b64651 Mon Sep 17 00:00:00 2001 From: sofia Date: Mon, 4 Aug 2025 00:07:31 +0300 Subject: [PATCH] Add refactoring and go-to-definition for multifile --- reid-lsp/src/main.rs | 153 +++++++++++++++++++++++-------------------- 1 file changed, 83 insertions(+), 70 deletions(-) diff --git a/reid-lsp/src/main.rs b/reid-lsp/src/main.rs index 8e47d08..834c89f 100644 --- a/reid-lsp/src/main.rs +++ b/reid-lsp/src/main.rs @@ -27,7 +27,7 @@ mod analysis; struct Backend { client: Client, analysis: DashMap, - module_to_url: DashMap, + module_to_path: DashMap, path_to_module: DashMap, module_id_counter: Mutex, } @@ -80,6 +80,8 @@ impl LanguageServer for Backend { }, )), references_provider: Some(OneOf::Left(true)), + definition_provider: Some(OneOf::Left(true)), + rename_provider: Some(OneOf::Left(true)), ..Default::default() }; Ok(InitializeResult { @@ -250,34 +252,34 @@ impl LanguageServer for Backend { }))) } - // async fn goto_definition(&self, params: GotoDefinitionParams) -> jsonrpc::Result> { - // let path = PathBuf::from(params.text_document_position_params.text_document.uri.path()); - // let analysis = self.analysis.get(&path); - // let position = params.text_document_position_params.position; + async fn goto_definition(&self, params: GotoDefinitionParams) -> jsonrpc::Result> { + let path = PathBuf::from(params.text_document_position_params.text_document.uri.path()); + let analysis = self.analysis.get(&path); + let position = params.text_document_position_params.position; - // if let Some(analysis) = &analysis { - // let token = analysis.tokens.iter().enumerate().find(|(_, tok)| { - // tok.position.1 == position.line + 1 - // && (tok.position.0 <= position.character + 1 - // && (tok.position.0 + tok.token.len() as u32) > position.character + 1) - // }); + if let Some(analysis) = &analysis { + let token = analysis.tokens.iter().enumerate().find(|(_, tok)| { + tok.position.1 == position.line + 1 + && (tok.position.0 <= position.character + 1 + && (tok.position.0 + tok.token.len() as u32) > position.character + 1) + }); - // if let Some(token) = token { - // if let Some((module_id, def_token)) = analysis.find_definition(token.0, &self.state_map()) { - // return if let Some(path) = self.module_to_url.get(&module_id) { - // Ok(Some(GotoDefinitionResponse::Scalar(lsp_types::Location { - // uri: Url::from_file_path(path.value()).unwrap(), - // range: token_to_range(def_token), - // }))) - // } else { - // Ok(None) - // }; - // } - // } - // }; + if let Some(token) = token { + if let Some((module_id, def_token)) = analysis.find_definition(token.0, &self.state_map()) { + return if let Some(path) = self.module_to_path.get(&module_id) { + Ok(Some(GotoDefinitionResponse::Scalar(lsp_types::Location { + uri: Url::from_file_path(path.value()).unwrap(), + range: token_to_range(def_token), + }))) + } else { + Ok(None) + }; + } + } + }; - // Ok(None) - // } + Ok(None) + } async fn references(&self, params: ReferenceParams) -> jsonrpc::Result>> { let path = PathBuf::from(params.text_document_position.text_document.uri.path()); @@ -296,7 +298,7 @@ impl LanguageServer for Backend { let mut locations = Vec::new(); if let Some(reference_tokens) = reference_tokens { for (module_id, symbol_idx) in reference_tokens { - if let Some(path) = self.module_to_url.get(&module_id) { + if let Some(path) = self.module_to_path.get(&module_id) { let url = Url::from_file_path(path.value()).unwrap(); if let Some(inner_analysis) = self.analysis.get(path.value()) { if let Some(token_idx) = inner_analysis.state.symbol_to_token.get(&symbol_idx) { @@ -320,48 +322,59 @@ impl LanguageServer for Backend { } } - // async fn rename(&self, params: RenameParams) -> jsonrpc::Result> { - // let path = PathBuf::from(params.text_document_position.text_document.uri.path()); - // let analysis = self.analysis.get(&path); - // let position = params.text_document_position.position; + async fn rename(&self, params: RenameParams) -> jsonrpc::Result> { + let path = PathBuf::from(params.text_document_position.text_document.uri.path()); + let analysis = self.analysis.get(&path); + let position = params.text_document_position.position; - // if let Some(analysis) = &analysis { - // let token = analysis.tokens.iter().enumerate().find(|(_, tok)| { - // tok.position.1 == position.line + 1 - // && (tok.position.0 <= position.character + 1 - // && (tok.position.0 + tok.token.len() as u32) > position.character + 1) - // }); - // if let Some(token) = token { - // let tokens = analysis.find_references(token.0, &self.state_map()).map(|symbols| { - // symbols - // .iter() - // .map(|symbol_id| analysis.state.symbol_to_token.get(&symbol_id).cloned().unwrap()) - // .collect::>() - // }); - // let mut edits = Vec::new(); - // if let Some(tokens) = tokens { - // for token_idx in tokens { - // let token = analysis.tokens.get(token_idx).unwrap(); - // edits.push(TextEdit { - // range: token_to_range(token), - // new_text: params.new_name.clone(), - // }); - // } - // } - // let mut changes = HashMap::new(); - // changes.insert(params.text_document_position.text_document.uri, edits); - // Ok(Some(WorkspaceEdit { - // changes: Some(changes), - // document_changes: None, - // change_annotations: None, - // })) - // } else { - // Ok(None) - // } - // } else { - // Ok(None) - // } - // } + if let Some(analysis) = &analysis { + let token = analysis.tokens.iter().enumerate().find(|(_, tok)| { + tok.position.1 == position.line + 1 + && (tok.position.0 <= position.character + 1 + && (tok.position.0 + tok.token.len() as u32) > position.character + 1) + }); + if let Some(token) = token { + let symbols = analysis.find_references(token.0, &self.state_map()); + let mut changes: HashMap> = HashMap::new(); + if let Some(symbols) = symbols { + for (module_id, symbol_id) in symbols { + let path = self.module_to_path.get(&module_id); + if let Some(path) = path { + let url = Url::from_file_path(path.value()).unwrap(); + let analysis = self.analysis.get(&path.clone()); + + if let Some(analysis) = analysis { + if let Some(token_idx) = analysis.state.symbol_to_token.get(&symbol_id) { + let token = analysis.tokens.get(*token_idx).unwrap(); + + // edits = changes.get(k) + let edit = TextEdit { + range: token_to_range(token), + new_text: params.new_name.clone(), + }; + if let Some(edits) = changes.get_mut(&url) { + edits.push(edit); + } else { + changes.insert(url, vec![edit]); + } + } + } + } + } + } + + Ok(Some(WorkspaceEdit { + changes: Some(changes), + document_changes: None, + change_annotations: None, + })) + } else { + Ok(None) + } + } else { + Ok(None) + } + } } fn token_to_range(token: &FullToken) -> lsp_types::Range { @@ -409,7 +422,7 @@ impl Backend { let module_id = lock.increment(); drop(lock); self.path_to_module.insert(file_path.clone(), module_id); - self.module_to_url.insert(module_id, file_path.clone()); + self.module_to_path.insert(module_id, file_path.clone()); module_id }; @@ -510,7 +523,7 @@ async fn main() { let (service, socket) = LspService::new(|client| Backend { client, analysis: DashMap::new(), - module_to_url: DashMap::new(), + module_to_path: DashMap::new(), path_to_module: DashMap::new(), module_id_counter: Mutex::new(SourceModuleId(0)), });