diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2023-03-15 10:34:23 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-15 14:34:23 +0000 |
commit | 7070b8ed50f13d95d926b19ed7d7ce9fc0d6d4f3 (patch) | |
tree | 1cba1972e1b7fcea1706a893984a3be12093cf1c /cli/lsp/language_server.rs | |
parent | 2ca160702795bb1b92196a848f7e4814d23ed32c (diff) |
fix(lsp): avoid calling client while holding lock (#18197)
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r-- | cli/lsp/language_server.rs | 566 |
1 files changed, 325 insertions, 241 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 50cc0326e..fc87001af 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -75,6 +75,7 @@ use crate::cache::HttpCache; use crate::file_fetcher::FileFetcher; use crate::graph_util; use crate::http_util::HttpClient; +use crate::lsp::urls::LspUrlKind; use crate::npm::create_npm_fs_resolver; use crate::npm::NpmCache; use crate::npm::NpmPackageResolver; @@ -84,7 +85,6 @@ use crate::proc_state::ProcState; use crate::tools::fmt::format_file; use crate::tools::fmt::format_parsed_source; use crate::util::fs::remove_dir_all_if_exists; -use crate::util::path::ensure_directory_specifier; use crate::util::path::specifier_to_file_path; use crate::util::progress_bar::ProgressBar; use crate::util::progress_bar::ProgressBarStyle; @@ -214,8 +214,7 @@ impl LanguageServer { .read() .await .client - .show_message(MessageType::WARNING, err) - .await; + .show_message(MessageType::WARNING, err); return Err(LspError::internal_error()); } } @@ -233,8 +232,7 @@ impl LanguageServer { .read() .await .client - .show_message(MessageType::WARNING, err) - .await; + .show_message(MessageType::WARNING, err); } // do npm resolution in a write—we should have everything // cached by this point anyway @@ -323,6 +321,92 @@ impl LanguageServer { None => Err(LspError::invalid_params("Missing parameters")), } } + + pub async fn refresh_specifiers_from_client(&self) -> bool { + let (client, specifiers) = + { + let ls = self.0.read().await; + let specifiers = + if ls.config.client_capabilities.workspace_configuration { + let root_capacity = match &ls.config.workspace_folders { + Some(folder) => folder.len(), + None => 1, + }; + let config_specifiers = ls.config.get_specifiers(); + let mut specifiers = + HashMap::with_capacity(root_capacity + config_specifiers.len()); + match &ls.config.workspace_folders { + Some(entry) => { + for (specifier, folder) in entry { + specifiers.insert(specifier.clone(), folder.uri.clone()); + } + } + None => { + if let Some(root_uri) = &ls.config.root_uri { + specifiers.insert( + root_uri.clone(), + ls.url_map.normalize_specifier(root_uri).unwrap(), + ); + } + } + } + specifiers.extend(ls.config.get_specifiers().iter().map(|s| { + (s.clone(), ls.url_map.normalize_specifier(s).unwrap()) + })); + + Some(specifiers.into_iter().collect::<Vec<_>>()) + } else { + None + }; + + (ls.client.clone(), specifiers) + }; + + let mut touched = false; + if let Some(specifiers) = specifiers { + let configs_result = client + .when_outside_lsp_lock() + .specifier_configurations( + specifiers + .iter() + .map(|(_, client_uri)| client_uri.clone()) + .collect(), + ) + .await; + + let mut ls = self.0.write().await; + if let Ok(configs) = configs_result { + for (value, internal_uri) in + configs.into_iter().zip(specifiers.into_iter().map(|s| s.1)) + { + match value { + Ok(specifier_settings) => { + if ls + .config + .set_specifier_settings(internal_uri, specifier_settings) + { + touched = true; + } + } + Err(err) => { + error!("{}", err); + } + } + } + } + + if ls.config.update_enabled_paths() { + touched = true; + } + + if touched { + ls.refresh_documents_config(); + ls.diagnostics_server.invalidate_all(); + ls.send_diagnostics_update(); + } + } + touched + } } fn create_lsp_structs( @@ -923,7 +1007,7 @@ impl Inner { tsconfig.merge(&unstable_libs); } if let Err(err) = self.merge_user_tsconfig(&mut tsconfig) { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } let _ok: bool = self .ts_server @@ -978,8 +1062,7 @@ impl Inner { // sometimes this root uri may not have a trailing slash, so force it to self.config.root_uri = params .root_uri - .map(|s| self.url_map.normalize_url(&s)) - .map(ensure_directory_specifier); + .map(|s| self.url_map.normalize_url(&s, LspUrlKind::Folder)); if let Some(value) = params.initialization_options { self.config.set_workspace_settings(value).map_err(|err| { @@ -990,7 +1073,12 @@ impl Inner { self.config.workspace_folders = params.workspace_folders.map(|folders| { folders .into_iter() - .map(|folder| (self.url_map.normalize_url(&folder.uri), folder)) + .map(|folder| { + ( + self.url_map.normalize_url(&folder.uri, LspUrlKind::Folder), + folder, + ) + }) .collect() }); self.config.update_capabilities(¶ms.capabilities); @@ -999,16 +1087,16 @@ impl Inner { self.update_debug_flag(); // Check to see if we need to change the cache path if let Err(err) = self.update_cache() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_config_file() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_package_json() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_tsconfig().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if capabilities.code_action_provider.is_some() { @@ -1025,20 +1113,14 @@ impl Inner { // Check to see if we need to setup the import map if let Err(err) = self.update_import_map().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } // Check to see if we need to setup any module registries if let Err(err) = self.update_registries().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } - self.documents.update_config( - self.maybe_import_map.clone(), - self.maybe_config_file.as_ref(), - self.maybe_package_json.as_ref(), - self.npm_api.clone(), - self.npm_resolution.clone(), - ); + // self.refresh_documents_config(); // todo(THIS PR): REMOVE self.assets.intitialize(self.snapshot()).await; self.performance.measure(mark); @@ -1049,47 +1131,14 @@ impl Inner { }) } - async fn initialized(&mut self, _: InitializedParams) { - if self - .config - .client_capabilities - .workspace_did_change_watched_files - { - // we are going to watch all the JSON files in the workspace, and the - // notification handler will pick up any of the changes of those files we - // are interested in. - let watch_registration_options = - DidChangeWatchedFilesRegistrationOptions { - watchers: vec![FileSystemWatcher { - glob_pattern: "**/*.{json,jsonc}".to_string(), - kind: Some(WatchKind::Change), - }], - }; - let registration = Registration { - id: "workspace/didChangeWatchedFiles".to_string(), - method: "workspace/didChangeWatchedFiles".to_string(), - register_options: Some( - serde_json::to_value(watch_registration_options).unwrap(), - ), - }; - if let Err(err) = - self.client.register_capability(vec![registration]).await - { - warn!("Client errored on capabilities.\n{:#}", err); - } - } - self.config.update_enabled_paths(self.client.clone()).await; - - if self.config.client_capabilities.testing_api { - let test_server = testing::TestServer::new( - self.client.clone(), - self.performance.clone(), - self.config.root_uri.clone(), - ); - self.maybe_testing_server = Some(test_server); - } - - lsp_log!("Server ready."); + fn refresh_documents_config(&mut self) { + self.documents.update_config( + self.maybe_import_map.clone(), + self.maybe_config_file.as_ref(), + self.maybe_package_json.as_ref(), + self.npm_api.clone(), + self.npm_resolution.clone(), + ); } async fn shutdown(&self) -> LspResult<()> { @@ -1130,7 +1179,9 @@ impl Inner { async fn did_change(&mut self, params: DidChangeTextDocumentParams) { let mark = self.performance.mark("did_change", Some(¶ms)); - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); match self.documents.change( &specifier, params.text_document.version, @@ -1166,7 +1217,9 @@ impl Inner { // already managed by the language service return; } - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if let Err(err) = self.documents.close(&specifier) { error!("{}", err); @@ -1206,31 +1259,25 @@ impl Inner { self.update_debug_flag(); if let Err(err) = self.update_cache() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_registries().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_config_file() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_package_json() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_import_map().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_tsconfig().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } - self.documents.update_config( - self.maybe_import_map.clone(), - self.maybe_config_file.as_ref(), - self.maybe_package_json.as_ref(), - self.npm_api.clone(), - self.npm_resolution.clone(), - ); + self.refresh_documents_config(); self.send_diagnostics_update(); self.send_testing_update(); @@ -1247,17 +1294,17 @@ impl Inner { let changes: HashSet<Url> = params .changes .iter() - .map(|f| self.url_map.normalize_url(&f.uri)) + .map(|f| self.url_map.normalize_url(&f.uri, LspUrlKind::File)) .collect(); // if the current deno.json has changed, we need to reload it if let Some(config_file) = &self.maybe_config_file { if changes.contains(&config_file.specifier) { if let Err(err) = self.update_config_file() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } if let Err(err) = self.update_tsconfig().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } touched = true; } @@ -1266,7 +1313,7 @@ impl Inner { // always update the package json if the deno config changes if touched || changes.contains(&package_json.specifier()) { if let Err(err) = self.update_package_json() { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } touched = true; } @@ -1276,19 +1323,13 @@ impl Inner { if let Some(import_map_uri) = &self.maybe_import_map_uri { if touched || changes.contains(import_map_uri) { if let Err(err) = self.update_import_map().await { - self.client.show_message(MessageType::WARNING, err).await; + self.client.show_message(MessageType::WARNING, err); } touched = true; } } if touched { - self.documents.update_config( - self.maybe_import_map.clone(), - self.maybe_config_file.as_ref(), - self.maybe_package_json.as_ref(), - self.npm_api.clone(), - self.npm_resolution.clone(), - ); + self.refresh_documents_config(); self.refresh_npm_specifiers().await; self.diagnostics_server.invalidate_all(); self.restart_ts_server().await; @@ -1298,18 +1339,20 @@ impl Inner { self.performance.measure(mark); } - async fn did_change_workspace_folders( + fn did_change_workspace_folders( &mut self, params: DidChangeWorkspaceFoldersParams, ) { - let mark = self - .performance - .mark("did_change_workspace_folders", Some(¶ms)); let mut workspace_folders = params .event .added .into_iter() - .map(|folder| (self.url_map.normalize_url(&folder.uri), folder)) + .map(|folder| { + ( + self.url_map.normalize_url(&folder.uri, LspUrlKind::Folder), + folder, + ) + }) .collect::<Vec<(ModuleSpecifier, WorkspaceFolder)>>(); if let Some(current_folders) = &self.config.workspace_folders { for (specifier, folder) in current_folders { @@ -1323,14 +1366,15 @@ impl Inner { } self.config.workspace_folders = Some(workspace_folders); - self.performance.measure(mark); } async fn document_symbol( &self, params: DocumentSymbolParams, ) -> LspResult<Option<DocumentSymbolResponse>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -1368,7 +1412,9 @@ impl Inner { &self, params: DocumentFormattingParams, ) -> LspResult<Option<Vec<TextEdit>>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); let document = match self.documents.get(&specifier) { Some(doc) if doc.is_open() => doc, _ => return Ok(None), @@ -1425,15 +1471,16 @@ impl Inner { Ok(Some(text_edits)) } } else { - self.client.show_message(MessageType::WARNING, format!("Unable to format \"{specifier}\". Likely due to unrecoverable syntax errors in the file.")).await; + self.client.show_message(MessageType::WARNING, format!("Unable to format \"{specifier}\". Likely due to unrecoverable syntax errors in the file.")); Ok(None) } } async fn hover(&self, params: HoverParams) -> LspResult<Option<Hover>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -1518,7 +1565,9 @@ impl Inner { &self, params: CodeActionParams, ) -> LspResult<Option<CodeActionResponse>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -1778,7 +1827,9 @@ impl Inner { &self, params: CodeLensParams, ) -> LspResult<Option<Vec<CodeLens>>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) || !(self.config.get_workspace_settings().enabled_code_lens() @@ -1838,9 +1889,10 @@ impl Inner { &self, params: DocumentHighlightParams, ) -> LspResult<Option<Vec<DocumentHighlight>>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -1882,9 +1934,10 @@ impl Inner { &self, params: ReferenceParams, ) -> LspResult<Option<Vec<Location>>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -1938,9 +1991,10 @@ impl Inner { &self, params: GotoDefinitionParams, ) -> LspResult<Option<GotoDefinitionResponse>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -1977,9 +2031,10 @@ impl Inner { &self, params: GotoTypeDefinitionParams, ) -> LspResult<Option<GotoTypeDefinitionResponse>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2024,9 +2079,10 @@ impl Inner { &self, params: CompletionParams, ) -> LspResult<Option<CompletionResponse>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2043,7 +2099,7 @@ impl Inner { &specifier, ¶ms.text_document_position.position, &self.config.snapshot(), - self.client.clone(), + &self.client, &self.module_registries, &self.documents, self.maybe_import_map.clone(), @@ -2183,9 +2239,10 @@ impl Inner { &self, params: GotoImplementationParams, ) -> LspResult<Option<GotoImplementationResponse>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2229,7 +2286,9 @@ impl Inner { &self, params: FoldingRangeParams, ) -> LspResult<Option<Vec<FoldingRange>>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2273,7 +2332,9 @@ impl Inner { &self, params: CallHierarchyIncomingCallsParams, ) -> LspResult<Option<Vec<CallHierarchyIncomingCall>>> { - let specifier = self.url_map.normalize_url(¶ms.item.uri); + let specifier = self + .url_map + .normalize_url(¶ms.item.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2319,7 +2380,9 @@ impl Inner { &self, params: CallHierarchyOutgoingCallsParams, ) -> LspResult<Option<Vec<CallHierarchyOutgoingCall>>> { - let specifier = self.url_map.normalize_url(¶ms.item.uri); + let specifier = self + .url_map + .normalize_url(¶ms.item.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2366,9 +2429,10 @@ impl Inner { &self, params: CallHierarchyPrepareParams, ) -> LspResult<Option<Vec<CallHierarchyItem>>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2434,9 +2498,10 @@ impl Inner { &self, params: RenameParams, ) -> LspResult<Option<WorkspaceEdit>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2486,7 +2551,9 @@ impl Inner { &self, params: SelectionRangeParams, ) -> LspResult<Option<Vec<SelectionRange>>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2524,7 +2591,9 @@ impl Inner { &self, params: SemanticTokensParams, ) -> LspResult<Option<SemanticTokensResult>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2566,7 +2635,9 @@ impl Inner { &self, params: SemanticTokensRangeParams, ) -> LspResult<Option<SemanticTokensRangeResult>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2609,9 +2680,10 @@ impl Inner { &self, params: SignatureHelpParams, ) -> LspResult<Option<SignatureHelp>> { - let specifier = self - .url_map - .normalize_url(¶ms.text_document_position_params.text_document.uri); + let specifier = self.url_map.normalize_url( + ¶ms.text_document_position_params.text_document.uri, + LspUrlKind::File, + ); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) { @@ -2728,8 +2800,61 @@ impl tower_lsp::LanguageServer for LanguageServer { language_server.initialize(params).await } - async fn initialized(&self, params: InitializedParams) { - self.0.write().await.initialized(params).await + async fn initialized(&self, _: InitializedParams) { + let mut maybe_registration = None; + let client = { + let mut ls = self.0.write().await; + if ls + .config + .client_capabilities + .workspace_did_change_watched_files + { + // we are going to watch all the JSON files in the workspace, and the + // notification handler will pick up any of the changes of those files we + // are interested in. + let watch_registration_options = + DidChangeWatchedFilesRegistrationOptions { + watchers: vec![FileSystemWatcher { + glob_pattern: "**/*.{json,jsonc}".to_string(), + kind: Some(WatchKind::Change), + }], + }; + maybe_registration = Some(Registration { + id: "workspace/didChangeWatchedFiles".to_string(), + method: "workspace/didChangeWatchedFiles".to_string(), + register_options: Some( + serde_json::to_value(watch_registration_options).unwrap(), + ), + }); + } + + if ls.config.client_capabilities.testing_api { + let test_server = testing::TestServer::new( + ls.client.clone(), + ls.performance.clone(), + ls.config.root_uri.clone(), + ); + ls.maybe_testing_server = Some(test_server); + } + ls.client.clone() + }; + + if let Some(registration) = maybe_registration { + if let Err(err) = client + .when_outside_lsp_lock() + .register_capability(vec![registration]) + .await + { + warn!("Client errored on capabilities.\n{:#}", err); + } + } + + if !self.refresh_specifiers_from_client().await { + // force update config + self.0.write().await.refresh_documents_config(); + } + + lsp_log!("Server ready."); } async fn shutdown(&self) -> LspResult<()> { @@ -2744,11 +2869,12 @@ impl tower_lsp::LanguageServer for LanguageServer { return; } - let (client, uri, specifier, had_specifier_settings) = { + let (client, client_uri, specifier, had_specifier_settings) = { let mut inner = self.0.write().await; let client = inner.client.clone(); - let uri = params.text_document.uri.clone(); - let specifier = inner.url_map.normalize_url(&uri); + let client_uri = params.text_document.uri.clone(); + let specifier = + inner.url_map.normalize_url(&client_uri, LspUrlKind::File); let document = inner.did_open(&specifier, params).await; let has_specifier_settings = inner.config.has_specifier_settings(&specifier); @@ -2762,39 +2888,38 @@ impl tower_lsp::LanguageServer for LanguageServer { inner.send_testing_update(); } } - (client, uri, specifier, has_specifier_settings) + (client, client_uri, specifier, has_specifier_settings) }; // retrieve the specifier settings outside the lock if - // they haven't been asked for yet on its own time + // they haven't been asked for yet if !had_specifier_settings { - let language_server = self.clone(); - tokio::spawn(async move { - let response = client.specifier_configuration(&uri).await; - let mut inner = language_server.0.write().await; - match response { - Ok(specifier_settings) => { - // now update the config and send a diagnostics update - inner.config.set_specifier_settings( - specifier.clone(), - uri, - specifier_settings, - ); - } - Err(err) => { - error!("{}", err); - } + let response = client + .when_outside_lsp_lock() + .specifier_configuration(&client_uri) + .await; + let mut ls = self.0.write().await; + match response { + Ok(specifier_settings) => { + ls.config + .set_specifier_settings(specifier.clone(), specifier_settings); + ls.config.update_enabled_paths(); } - if inner - .documents - .get(&specifier) - .map(|d| d.is_diagnosable()) - .unwrap_or(false) - { - inner.send_diagnostics_update(); - inner.send_testing_update(); + Err(err) => { + error!("{}", err); } - }); + } + + if ls + .documents + .get(&specifier) + .map(|d| d.is_diagnosable()) + .unwrap_or(false) + { + ls.refresh_documents_config(); + ls.send_diagnostics_update(); + ls.send_testing_update(); + } } } @@ -2815,66 +2940,18 @@ impl tower_lsp::LanguageServer for LanguageServer { &self, params: DidChangeConfigurationParams, ) { - let (has_workspace_capability, client, specifiers, mark) = { - let inner = self.0.write().await; - let mark = inner - .performance - .mark("did_change_configuration", Some(¶ms)); - - let specifiers = - if inner.config.client_capabilities.workspace_configuration { - Some(inner.config.get_specifiers_with_client_uris()) - } else { - None - }; + let (mark, has_workspace_capability, client) = { + let inner = self.0.read().await; ( + inner + .performance + .mark("did_change_configuration", Some(¶ms)), inner.config.client_capabilities.workspace_configuration, inner.client.clone(), - specifiers, - mark, ) }; - // start retrieving all the specifiers' settings outside the lock on its own - // time - if let Some(specifiers) = specifiers { - let language_server = self.clone(); - let client = client.clone(); - tokio::spawn(async move { - if let Ok(configs) = client - .specifier_configurations( - specifiers.iter().map(|s| s.client_uri.clone()).collect(), - ) - .await - { - let mut inner = language_server.0.write().await; - for (i, value) in configs.into_iter().enumerate() { - match value { - Ok(specifier_settings) => { - let entry = specifiers[i].clone(); - inner.config.set_specifier_settings( - entry.specifier, - entry.client_uri, - specifier_settings, - ); - } - Err(err) => { - error!("{}", err); - } - } - } - } - let mut ls = language_server.0.write().await; - if ls.config.update_enabled_paths(client).await { - ls.diagnostics_server.invalidate_all(); - // this will be called in the inner did_change_configuration, but the - // problem then becomes, if there was a change, the snapshot used - // will be an out of date one, so we will call it again here if the - // workspace folders have been touched - ls.send_diagnostics_update(); - } - }); - } + self.refresh_specifiers_from_client().await; // Get the configuration from the client outside of the lock // in order to prevent potential deadlocking scenarios where @@ -2884,7 +2961,10 @@ impl tower_lsp::LanguageServer for LanguageServer { // received and acquiring the lock, but most likely there // won't be any racing here. let client_workspace_config = if has_workspace_capability { - let config_response = client.workspace_configuration().await; + let config_response = client + .when_outside_lsp_lock() + .workspace_configuration() + .await; match config_response { Ok(value) => Some(value), Err(err) => { @@ -2915,19 +2995,17 @@ impl tower_lsp::LanguageServer for LanguageServer { &self, params: DidChangeWorkspaceFoldersParams, ) { - let client = { - let mut inner = self.0.write().await; - inner.did_change_workspace_folders(params).await; - inner.client.clone() + let (performance, mark) = { + let mut ls = self.0.write().await; + let mark = ls + .performance + .mark("did_change_workspace_folders", Some(¶ms)); + ls.did_change_workspace_folders(params); + (ls.performance.clone(), mark) }; - let language_server = self.clone(); - tokio::spawn(async move { - let mut ls = language_server.0.write().await; - if ls.config.update_enabled_paths(client).await { - ls.diagnostics_server.invalidate_all(); - ls.send_diagnostics_update(); - } - }); + + self.refresh_specifiers_from_client().await; + performance.measure(mark); } async fn document_symbol( @@ -3106,7 +3184,9 @@ impl Inner { &self, params: lsp_custom::CacheParams, ) -> Result<Option<PrepareCacheResult>, AnyError> { - let referrer = self.url_map.normalize_url(¶ms.referrer.uri); + let referrer = self + .url_map + .normalize_url(¶ms.referrer.uri, LspUrlKind::File); if !self.is_diagnosable(&referrer) { return Ok(None); } @@ -3116,7 +3196,7 @@ impl Inner { params .uris .iter() - .map(|t| self.url_map.normalize_url(&t.uri)) + .map(|t| self.url_map.normalize_url(&t.uri, LspUrlKind::File)) .collect() } else { vec![referrer] @@ -3190,7 +3270,9 @@ impl Inner { &self, params: InlayHintParams, ) -> LspResult<Option<Vec<InlayHint>>> { - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); let workspace_settings = self.config.get_workspace_settings(); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) @@ -3251,7 +3333,9 @@ impl Inner { let mark = self .performance .mark("virtual_text_document", Some(¶ms)); - let specifier = self.url_map.normalize_url(¶ms.text_document.uri); + let specifier = self + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); let contents = if specifier.as_str() == "deno:/status.md" { let mut contents = String::new(); let mut documents_specifiers = self |