diff options
author | hrsh7th <hrsh7th@gmail.com> | 2020-12-30 09:58:20 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-30 11:58:20 +1100 |
commit | 57b0562957f0887611526bf7e878ac34fdcd6393 (patch) | |
tree | cf419c9892b2d0275a7d9ffa79a4e79728fd5b97 /cli/lsp/language_server.rs | |
parent | d5f3a749eb9b86ed24378a3ee39ee443c374da53 (diff) |
feat(lsp): Implement textDocument/rename (#8910)
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r-- | cli/lsp/language_server.rs | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 72d1b1ad3..9591f246a 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -802,6 +802,78 @@ impl lspower::LanguageServer for LanguageServer { } } + async fn rename( + &self, + params: RenameParams, + ) -> LSPResult<Option<WorkspaceEdit>> { + if !self.enabled() { + return Ok(None); + } + + let snapshot = self.snapshot(); + let specifier = + utils::normalize_url(params.text_document_position.text_document.uri); + + let line_index = + self + .get_line_index(specifier.clone()) + .await + .map_err(|err| { + error!("Failed to get line_index {:#?}", err); + LSPError::internal_error() + })?; + + let req = tsc::RequestMethod::FindRenameLocations(( + specifier, + text::to_char_pos(&line_index, params.text_document_position.position), + true, + true, + false, + )); + + let res = self + .ts_server + .request(snapshot.clone(), req) + .await + .map_err(|err| { + error!("Failed to request to tsserver {:#?}", err); + LSPError::invalid_request() + })?; + + let maybe_locations = serde_json::from_value::< + Option<Vec<tsc::RenameLocation>>, + >(res) + .map_err(|err| { + error!( + "Failed to deserialize tsserver response to Vec<RenameLocation> {:#?}", + err + ); + LSPError::internal_error() + })?; + + match maybe_locations { + Some(locations) => { + let rename_locations = tsc::RenameLocations { locations }; + let workpace_edits = rename_locations + .into_workspace_edit( + snapshot, + |s| self.get_line_index(s), + ¶ms.new_name, + ) + .await + .map_err(|err| { + error!( + "Failed to convert tsc::RenameLocations to WorkspaceEdit {:#?}", + err + ); + LSPError::internal_error() + })?; + Ok(Some(workpace_edits)) + } + None => Ok(None), + } + } + async fn request_else( &self, method: &str, @@ -1143,4 +1215,57 @@ mod tests { ]); harness.run().await; } + #[tokio::test] + async fn test_rename() { + let mut harness = LspTestHarness::new(vec![ + ("initialize_request.json", LspResponse::RequestAny), + ("initialized_notification.json", LspResponse::None), + ("rename_did_open_notification.json", LspResponse::None), + ( + "rename_request.json", + LspResponse::Request( + 2, + json!({ + "documentChanges": [{ + "textDocument": { + "uri": "file:///a/file.ts", + "version": 1, + }, + "edits": [{ + "range": { + "start": { + "line": 0, + "character": 4 + }, + "end": { + "line": 0, + "character": 12 + } + }, + "newText": "variable_modified" + }, { + "range": { + "start": { + "line": 1, + "character": 12 + }, + "end": { + "line": 1, + "character": 20 + } + }, + "newText": "variable_modified" + }] + }] + }), + ), + ), + ( + "shutdown_request.json", + LspResponse::Request(3, json!(null)), + ), + ("exit_notification.json", LspResponse::None), + ]); + harness.run().await; + } } |