summaryrefslogtreecommitdiff
path: root/cli/lsp/language_server.rs
diff options
context:
space:
mode:
authorhrsh7th <hrsh7th@gmail.com>2020-12-30 09:58:20 +0900
committerGitHub <noreply@github.com>2020-12-30 11:58:20 +1100
commit57b0562957f0887611526bf7e878ac34fdcd6393 (patch)
treecf419c9892b2d0275a7d9ffa79a4e79728fd5b97 /cli/lsp/language_server.rs
parentd5f3a749eb9b86ed24378a3ee39ee443c374da53 (diff)
feat(lsp): Implement textDocument/rename (#8910)
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r--cli/lsp/language_server.rs125
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),
+ &params.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;
+ }
}