diff options
author | Kitson Kelly <me@kitsonkelly.com> | 2021-05-20 19:56:48 +1000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-20 19:56:48 +1000 |
commit | 014d8d51c0bfb10a8f47544a94d5a2b6cea7b578 (patch) | |
tree | e6967d9317c01cfb7f51990676502d4391f582a4 /cli/lsp/language_server.rs | |
parent | bdee065d424f4dcc45c9137ccd1d0d9e581d20ae (diff) |
fix(lsp): re-enable the per resource configuration without a deadlock (#10625)
Fixes #10603
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r-- | cli/lsp/language_server.rs | 206 |
1 files changed, 90 insertions, 116 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index f9bb52cbe..d86ccefd5 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -38,6 +38,7 @@ use super::analysis::ResolvedDependency; use super::capabilities; use super::completions; use super::config::Config; +use super::config::ConfigSnapshot; use super::config::SETTINGS_SECTION; use super::diagnostics; use super::diagnostics::DiagnosticSource; @@ -77,7 +78,7 @@ pub struct LanguageServer(Arc<tokio::sync::Mutex<Inner>>); #[derive(Debug, Clone, Default)] pub struct StateSnapshot { pub assets: Assets, - pub config: Config, + pub config: ConfigSnapshot, pub documents: DocumentCache, pub module_registries: registries::ModuleRegistry, pub performance: Performance, @@ -141,11 +142,12 @@ impl Inner { let ts_server = Arc::new(TsServer::new()); let performance = Performance::default(); let diagnostics_server = diagnostics::DiagnosticsServer::new(); + let config = Config::new(client.clone()); Self { assets: Default::default(), client, - config: Default::default(), + config, diagnostics_server, documents: Default::default(), maybe_config_uri: Default::default(), @@ -282,7 +284,7 @@ impl Inner { let navigation_tree: tsc::NavigationTree = self .ts_server .request( - self.snapshot(), + self.snapshot()?, tsc::RequestMethod::GetNavigationTree(specifier.clone()), ) .await?; @@ -294,16 +296,19 @@ impl Inner { } } - pub(crate) fn snapshot(&self) -> StateSnapshot { - StateSnapshot { + pub(crate) fn snapshot(&self) -> LspResult<StateSnapshot> { + Ok(StateSnapshot { assets: self.assets.clone(), - config: self.config.clone(), + config: self.config.snapshot().map_err(|err| { + error!("{}", err); + LspError::internal_error() + })?, documents: self.documents.clone(), module_registries: self.module_registries.clone(), performance: self.performance.clone(), sources: self.sources.clone(), url_map: self.url_map.clone(), - } + }) } pub async fn update_import_map(&mut self) -> Result<(), AnyError> { @@ -311,7 +316,7 @@ impl Inner { let (maybe_import_map, maybe_root_uri) = { let config = &self.config; ( - config.workspace_settings.import_map.clone(), + config.get_workspace_settings().import_map, config.root_uri.clone(), ) }; @@ -357,10 +362,11 @@ impl Inner { } pub fn update_debug_flag(&self) -> bool { + let internal_debug = self.config.get_workspace_settings().internal_debug; logger::LSP_DEBUG_FLAG .compare_exchange( - !self.config.workspace_settings.internal_debug, - self.config.workspace_settings.internal_debug, + !internal_debug, + internal_debug, Ordering::Acquire, Ordering::Relaxed, ) @@ -369,8 +375,13 @@ impl Inner { async fn update_registries(&mut self) -> Result<(), AnyError> { let mark = self.performance.mark("update_registries", None::<()>); - for (registry, enabled) in - self.config.workspace_settings.suggest.imports.hosts.iter() + for (registry, enabled) in self + .config + .get_workspace_settings() + .suggest + .imports + .hosts + .iter() { if *enabled { info!("Enabling auto complete registry for: {}", registry); @@ -401,16 +412,14 @@ impl Inner { })); let (maybe_config, maybe_root_uri) = { let config = &self.config; - if config.workspace_settings.unstable { + let workspace_settings = config.get_workspace_settings(); + if workspace_settings.unstable { let unstable_libs = json!({ "lib": ["deno.ns", "deno.window", "deno.unstable"] }); tsconfig.merge(&unstable_libs); } - ( - config.workspace_settings.config.clone(), - config.root_uri.clone(), - ) + (workspace_settings.config, config.root_uri.clone()) }; if let Some(config_str) = &maybe_config { info!("Updating TypeScript configuration from: \"{}\"", config_str); @@ -443,7 +452,7 @@ impl Inner { } let _ok: bool = self .ts_server - .request(self.snapshot(), tsc::RequestMethod::Configure(tsconfig)) + .request(self.snapshot()?, tsc::RequestMethod::Configure(tsconfig)) .await?; self.performance.measure(mark); Ok(()) @@ -464,7 +473,7 @@ impl Inner { return Ok(maybe_asset.clone()); } else { let maybe_asset = - tsc::get_asset(&specifier, &self.ts_server, self.snapshot()).await?; + tsc::get_asset(&specifier, &self.ts_server, self.snapshot()?).await?; self.assets.insert(specifier.clone(), maybe_asset.clone()); Ok(maybe_asset) } @@ -507,7 +516,10 @@ impl Inner { let config = &mut self.config; config.root_uri = params.root_uri; if let Some(value) = params.initialization_options { - config.update_workspace(value)?; + config.set_workspace_settings(value).map_err(|err| { + error!("Cannot set workspace settings: {}", err); + LspError::internal_error() + })?; } config.update_capabilities(¶ms.capabilities); } @@ -520,7 +532,7 @@ impl Inner { if capabilities.code_action_provider.is_some() { let fixable_diagnostics: Vec<String> = self .ts_server - .request(self.snapshot(), tsc::RequestMethod::GetSupportedCodeFixes) + .request(self.snapshot()?, tsc::RequestMethod::GetSupportedCodeFixes) .await .map_err(|err| { error!("Unable to get fixable diagnostics: {}", err); @@ -592,27 +604,13 @@ impl Inner { let mark = self.performance.mark("did_open", Some(¶ms)); let specifier = self.url_map.normalize_url(¶ms.text_document.uri); - // we only query the individual resource file if the client supports it - // TODO(@kitsonk) workaround https://github.com/denoland/deno/issues/10603 - // if self.config.client_capabilities.workspace_configuration - // && !self.config.contains(&specifier) - // { - // if let Ok(value) = self - // .client - // .configuration(vec![ConfigurationItem { - // scope_uri: Some(params.text_document.uri.clone()), - // section: Some(SETTINGS_SECTION.to_string()), - // }]) - // .await - // { - // if let Err(err) = self - // .config - // .update_specifier(specifier.clone(), value[0].clone()) - // { - // warn!("Error updating specifier configuration: {}", err); - // } - // } - // } + if let Err(err) = self + .config + .update_specifier_settings(&specifier, ¶ms.text_document.uri) + .await + { + error!("Error updating specifier settings: {}", err); + } if params.text_document.uri.scheme() == "deno" { // we can ignore virtual text documents opening, as they don't need to @@ -679,32 +677,8 @@ impl Inner { .mark("did_change_configuration", Some(¶ms)); if self.config.client_capabilities.workspace_configuration { - let specifiers: Vec<ModuleSpecifier> = - self.config.specifier_settings.keys().cloned().collect(); - let mut snapshot = self.snapshot(); - let mut config_items = specifiers - .iter() - .map(|s| ConfigurationItem { - scope_uri: Some(snapshot.url_map.normalize_specifier(s).unwrap()), - section: Some(SETTINGS_SECTION.to_string()), - }) - .collect(); - let mut items = vec![ConfigurationItem { - scope_uri: None, - section: Some(SETTINGS_SECTION.to_string()), - }]; - items.append(&mut config_items); - if let Ok(configs) = self.client.configuration(items).await { - for (i, value) in configs.into_iter().enumerate() { - if let Err(err) = match i { - 0 => self.config.update_workspace(value), - _ => self - .config - .update_specifier(specifiers[i - 1].clone(), value), - } { - error!("failed to update settings: {}", err); - } - } + if let Err(err) = self.config.update_workspace_settings().await { + error!("Error updating workspace settings: {}", err); } } else if let Some(config) = params .settings @@ -713,7 +687,7 @@ impl Inner { .flatten() .cloned() { - if let Err(err) = self.config.update_workspace(config) { + if let Err(err) = self.config.set_workspace_settings(config) { error!("failed to update settings: {}", err); } } @@ -804,7 +778,7 @@ impl Inner { let req = tsc::RequestMethod::GetNavigationTree(specifier); let navigation_tree: tsc::NavigationTree = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -900,7 +874,7 @@ impl Inner { )); let maybe_quick_info: Option<tsc::QuickInfo> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Unable to get quick info: {}", err); @@ -977,7 +951,7 @@ impl Inner { codes, )); let actions: Vec<tsc::CodeFixAction> = - match self.ts_server.request(self.snapshot(), req).await { + match self.ts_server.request(self.snapshot()?, req).await { Ok(items) => items, Err(err) => { // sometimes tsc reports errors when retrieving code actions @@ -1040,7 +1014,7 @@ impl Inner { )); let combined_code_actions: tsc::CombinedCodeActions = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Unable to get combined fix from TypeScript: {}", err); @@ -1074,7 +1048,7 @@ impl Inner { ) -> LspResult<Option<Vec<CodeLens>>> { let specifier = self.url_map.normalize_url(¶ms.text_document.uri); if !self.config.specifier_enabled(&specifier) - || !self.config.workspace_settings.enabled_code_lens() + || !self.config.get_workspace_settings().enabled_code_lens() { return Ok(None); } @@ -1093,9 +1067,10 @@ impl Inner { let cl = Rc::new(RefCell::new(Vec::new())); navigation_tree.walk(&|i, mp| { let mut code_lenses = cl.borrow_mut(); + let workspace_settings = self.config.get_workspace_settings(); // TSC Implementations Code Lens - if self.config.workspace_settings.code_lens.implementations { + if workspace_settings.code_lens.implementations { let source = CodeLensSource::Implementations; match i.kind { tsc::ScriptElementKind::InterfaceElement => { @@ -1119,7 +1094,7 @@ impl Inner { } // TSC References Code Lens - if self.config.workspace_settings.code_lens.references { + if workspace_settings.code_lens.references { let source = CodeLensSource::References; if let Some(parent) = &mp { if parent.kind == tsc::ScriptElementKind::EnumElement { @@ -1128,12 +1103,7 @@ impl Inner { } match i.kind { tsc::ScriptElementKind::FunctionElement => { - if self - .config - .workspace_settings - .code_lens - .references_all_functions - { + if workspace_settings.code_lens.references_all_functions { code_lenses.push(i.to_code_lens( &line_index, &specifier, @@ -1214,12 +1184,14 @@ impl Inner { line_index.offset_tsc(params.range.start)?, )); let maybe_implementations: Option<Vec<tsc::ImplementationLocation>> = - self.ts_server.request(self.snapshot(), req).await.map_err( - |err| { + self + .ts_server + .request(self.snapshot()?, req) + .await + .map_err(|err| { error!("Error processing TypeScript request: {}", err); LspError::internal_error() - }, - )?; + })?; if let Some(implementations) = maybe_implementations { let mut locations = Vec::new(); for implementation in implementations { @@ -1292,13 +1264,14 @@ impl Inner { code_lens_data.specifier.clone(), line_index.offset_tsc(params.range.start)?, )); - let maybe_references: Option<Vec<tsc::ReferenceEntry>> = - self.ts_server.request(self.snapshot(), req).await.map_err( - |err| { - error!("Error processing TypeScript request: {}", err); - LspError::internal_error() - }, - )?; + let maybe_references: Option<Vec<tsc::ReferenceEntry>> = self + .ts_server + .request(self.snapshot()?, req) + .await + .map_err(|err| { + error!("Error processing TypeScript request: {}", err); + LspError::internal_error() + })?; if let Some(references) = maybe_references { let mut locations = Vec::new(); for reference in references { @@ -1408,7 +1381,7 @@ impl Inner { )); let maybe_document_highlights: Option<Vec<tsc::DocumentHighlights>> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Unable to get document highlights from TypeScript: {}", err); @@ -1455,7 +1428,7 @@ impl Inner { )); let maybe_references: Option<Vec<tsc::ReferenceEntry>> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Unable to get references from TypeScript: {}", err); @@ -1510,7 +1483,7 @@ impl Inner { )); let maybe_definition: Option<tsc::DefinitionInfoAndBoundSpan> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Unable to get definition from TypeScript: {}", err); @@ -1545,7 +1518,7 @@ impl Inner { let response = if let Some(response) = completions::get_import_completions( &specifier, ¶ms.text_document_position.position, - &self.snapshot(), + &self.snapshot()?, ) .await { @@ -1580,7 +1553,7 @@ impl Inner { )); let maybe_completion_info: Option<tsc::CompletionInfo> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Unable to get completion info from TypeScript: {}", err); @@ -1590,7 +1563,7 @@ impl Inner { if let Some(completions) = maybe_completion_info { let results = completions.as_completion_response( &line_index, - &self.config.workspace_settings.suggest, + &self.config.get_workspace_settings().suggest, &specifier, position, ); @@ -1618,13 +1591,14 @@ impl Inner { })?; if let Some(data) = data.tsc { let req = tsc::RequestMethod::GetCompletionDetails(data.into()); - let maybe_completion_info: Option<tsc::CompletionEntryDetails> = - self.ts_server.request(self.snapshot(), req).await.map_err( - |err| { - error!("Unable to get completion info from TypeScript: {}", err); - LspError::internal_error() - }, - )?; + let maybe_completion_info: Option<tsc::CompletionEntryDetails> = self + .ts_server + .request(self.snapshot()?, req) + .await + .map_err(|err| { + error!("Unable to get completion info from TypeScript: {}", err); + LspError::internal_error() + })?; if let Some(completion_info) = maybe_completion_info { completion_info.as_completion_item(¶ms) } else { @@ -1670,7 +1644,7 @@ impl Inner { )); let maybe_implementations: Option<Vec<tsc::ImplementationLocation>> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -1716,7 +1690,7 @@ impl Inner { let req = tsc::RequestMethod::GetOutliningSpans(specifier.clone()); let outlining_spans: Vec<tsc::OutliningSpan> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -1776,7 +1750,7 @@ impl Inner { )); let incoming_calls: Vec<tsc::CallHierarchyIncomingCall> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -1830,7 +1804,7 @@ impl Inner { )); let outgoing_calls: Vec<tsc::CallHierarchyOutgoingCall> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -1890,7 +1864,7 @@ impl Inner { let maybe_one_or_many: Option<tsc::OneOrMany<tsc::CallHierarchyItem>> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -1970,7 +1944,7 @@ impl Inner { let maybe_locations: Option<Vec<tsc::RenameLocation>> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -2057,7 +2031,7 @@ impl Inner { let selection_range: tsc::SelectionRange = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -2099,7 +2073,7 @@ impl Inner { )); let semantic_classification: tsc::Classifications = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -2147,7 +2121,7 @@ impl Inner { )); let semantic_classification: tsc::Classifications = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver {}", err); @@ -2204,7 +2178,7 @@ impl Inner { )); let maybe_signature_help_items: Option<tsc::SignatureHelpItems> = self .ts_server - .request(self.snapshot(), req) + .request(self.snapshot()?, req) .await .map_err(|err| { error!("Failed to request to tsserver: {}", err); |