diff options
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r-- | cli/lsp/language_server.rs | 251 |
1 files changed, 73 insertions, 178 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index e6e49c654..8afcc7ffc 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -23,6 +23,7 @@ use import_map::ImportMap; use indexmap::IndexSet; use log::error; use serde_json::from_value; +use std::collections::BTreeMap; use std::collections::HashMap; use std::collections::HashSet; use std::env; @@ -80,7 +81,6 @@ use super::tsc::AssetsSnapshot; use super::tsc::GetCompletionDetailsArgs; use super::tsc::TsServer; use super::urls; -use super::urls::LspClientUrl; use crate::args::get_root_cert_store; use crate::args::package_json; use crate::args::resolve_import_map_from_specifier; @@ -403,68 +403,42 @@ impl LanguageServer { } } - pub async fn refresh_specifiers_from_client(&self) -> bool { - let (client, specifiers) = { + pub async fn refresh_configuration(&self) { + let (client, folders, capable) = { let ls = self.0.read().await; - let specifiers = if ls.config.client_capabilities.workspace_configuration - { - let root_capacity = std::cmp::max(ls.config.workspace_folders.len(), 1); - let config_specifiers = ls.config.get_specifiers(); - let mut specifiers = - HashMap::with_capacity(root_capacity + config_specifiers.len()); - for (specifier, folder) in &ls.config.workspace_folders { - specifiers - .insert(specifier.clone(), LspClientUrl::new(folder.uri.clone())); - } - 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) + ( + ls.client.clone(), + ls.config.workspace_folders.clone(), + ls.config.client_capabilities.workspace_configuration, + ) }; - - let mut touched = false; - if let Some(specifiers) = specifiers { - let configs_result = client + if capable { + let mut scopes = Vec::with_capacity(folders.len() + 1); + scopes.push(None); + for (_, folder) in &folders { + scopes.push(Some(folder.uri.clone())); + } + let configs = client .when_outside_lsp_lock() - .specifier_configurations( - specifiers - .iter() - .map(|(_, client_uri)| client_uri.clone()) - .collect(), - ) + .workspace_configuration(scopes) .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.0)) - { - match value { - Ok(specifier_settings) => { - if ls - .config - .set_specifier_settings(internal_uri, specifier_settings) - { - touched = true; - } - } - Err(err) => { - error!("{}", err); - } - } + if let Ok(configs) = configs { + if configs.len() != folders.len() + 1 { + lsp_warn!("Incorrect number of configurations received."); + return; } + let mut configs = configs.into_iter(); + let unscoped = configs.next().unwrap(); + let mut by_workspace_folder = BTreeMap::new(); + for (folder_uri, _) in &folders { + by_workspace_folder + .insert(folder_uri.clone(), configs.next().unwrap()); + } + let mut ls = self.0.write().await; + ls.config + .set_workspace_settings(unscoped, Some(by_workspace_folder)); } } - touched } } @@ -1182,6 +1156,7 @@ impl Inner { if let Some(options) = params.initialization_options { self.config.set_workspace_settings( WorkspaceSettings::from_initialization_options(options), + None, ); } if let Some(folders) = params.workspace_folders { @@ -1391,27 +1366,22 @@ impl Inner { async fn did_change_configuration( &mut self, - client_workspace_config: Option<WorkspaceSettings>, params: DidChangeConfigurationParams, ) { - let maybe_config = - if self.config.client_capabilities.workspace_configuration { - client_workspace_config - } else { - params.settings.as_object().map(|settings| { - let deno = - serde_json::to_value(settings.get(SETTINGS_SECTION)).unwrap(); - let javascript = - serde_json::to_value(settings.get("javascript")).unwrap(); - let typescript = - serde_json::to_value(settings.get("typescript")).unwrap(); - WorkspaceSettings::from_raw_settings(deno, javascript, typescript) - }) - }; - - if let Some(settings) = maybe_config { - self.config.set_workspace_settings(settings); - } + if !self.config.client_capabilities.workspace_configuration { + let config = params.settings.as_object().map(|settings| { + let deno = + serde_json::to_value(settings.get(SETTINGS_SECTION)).unwrap(); + let javascript = + serde_json::to_value(settings.get("javascript")).unwrap(); + let typescript = + serde_json::to_value(settings.get("typescript")).unwrap(); + WorkspaceSettings::from_raw_settings(deno, javascript, typescript) + }); + if let Some(settings) = config { + self.config.set_workspace_settings(settings, None); + } + }; self.update_debug_flag(); if let Err(err) = self.update_cache().await { @@ -2148,8 +2118,7 @@ impl Inner { .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) - || !(self.config.workspace_settings().enabled_code_lens() - || self.config.specifier_code_lens_test(&specifier)) + || !self.config.enabled_code_lens_for_specifier(&specifier) { return Ok(None); } @@ -2385,10 +2354,8 @@ impl Inner { ¶ms.text_document_position.text_document.uri, LspUrlKind::File, ); - let language_settings = self - .config - .workspace_settings() - .language_settings_for_specifier(&specifier); + let language_settings = + self.config.language_settings_for_specifier(&specifier); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) || !language_settings.map(|s| s.suggest.enabled).unwrap_or(true) @@ -2457,7 +2424,6 @@ impl Inner { line_index, &self .config - .workspace_settings() .language_settings_for_specifier(&specifier) .cloned() .unwrap_or_default() @@ -2992,7 +2958,6 @@ impl Inner { ); let options = self .config - .workspace_settings() .language_settings_for_specifier(&old_specifier) .map(|s| s.update_imports_on_file_move.clone()) .unwrap_or_default(); @@ -3188,7 +3153,7 @@ impl tower_lsp::LanguageServer for LanguageServer { } } - self.refresh_specifiers_from_client().await; + self.refresh_configuration().await; { let mut ls = self.0.write().await; @@ -3212,58 +3177,17 @@ impl tower_lsp::LanguageServer for LanguageServer { return; } - let (client, client_uri, specifier, should_get_specifier_settings) = { - let mut inner = self.0.write().await; - let client = inner.client.clone(); - let client_uri = LspClientUrl::new(params.text_document.uri.clone()); - let specifier = inner - .url_map - .normalize_url(client_uri.as_url(), LspUrlKind::File); - let document = inner.did_open(&specifier, params).await; - let should_get_specifier_settings = - !inner.config.has_specifier_settings(&specifier) - && inner.config.client_capabilities.workspace_configuration; - if document.is_diagnosable() { - inner.refresh_npm_specifiers().await; - let specifiers = inner.documents.dependents(&specifier); - inner.diagnostics_server.invalidate(&specifiers); - // don't send diagnostics yet if we don't have the specifier settings - if !should_get_specifier_settings { - inner.send_diagnostics_update(); - inner.send_testing_update(); - } - } - (client, client_uri, specifier, should_get_specifier_settings) - }; - - // retrieve the specifier settings outside the lock if - // they haven't been asked for yet - if should_get_specifier_settings { - 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); - } - Err(err) => { - error!("{}", err); - } - } - - if ls - .documents - .get(&specifier) - .map(|d| d.is_diagnosable()) - .unwrap_or(false) - { - ls.refresh_documents_config().await; - ls.send_diagnostics_update(); - ls.send_testing_update(); - } + let mut inner = self.0.write().await; + let specifier = inner + .url_map + .normalize_url(¶ms.text_document.uri, LspUrlKind::File); + let document = inner.did_open(&specifier, params).await; + if document.is_diagnosable() { + inner.refresh_npm_specifiers().await; + let specifiers = inner.documents.dependents(&specifier); + inner.diagnostics_server.invalidate(&specifiers); + inner.send_diagnostics_update(); + inner.send_testing_update(); } } @@ -3277,7 +3201,10 @@ impl tower_lsp::LanguageServer for LanguageServer { let mut inner = self.0.write().await; let specifier = inner.url_map.normalize_url(uri, LspUrlKind::File); inner.documents.save(&specifier); - if !inner.config.workspace_settings().cache_on_save + if !inner + .config + .workspace_settings_for_specifier(&specifier) + .cache_on_save || !inner.config.specifier_enabled(&specifier) || !inner.diagnostics_state.has_no_cache_diagnostics(&specifier) { @@ -3310,47 +3237,17 @@ impl tower_lsp::LanguageServer for LanguageServer { &self, params: DidChangeConfigurationParams, ) { - let (mark, has_workspace_capability, client) = { + let mark = { let inner = self.0.read().await; - ( - inner - .performance - .mark("did_change_configuration", Some(¶ms)), - inner.config.client_capabilities.workspace_configuration, - inner.client.clone(), - ) + inner + .performance + .mark("did_change_configuration", Some(¶ms)) }; - self.refresh_specifiers_from_client().await; - - // Get the configuration from the client outside of the lock - // in order to prevent potential deadlocking scenarios where - // the server holds a lock and calls into the client, which - // calls into the server which deadlocks acquiring the lock. - // There is a gap here between when the configuration is - // 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 - .when_outside_lsp_lock() - .workspace_configuration() - .await; - match config_response { - Ok(settings) => Some(settings), - Err(err) => { - error!("{}", err); - None - } - } - } else { - None - }; + self.refresh_configuration().await; - // now update the inner state let mut inner = self.0.write().await; - inner - .did_change_configuration(client_workspace_config, params) - .await; + inner.did_change_configuration(params).await; inner.performance.measure(mark); } @@ -3374,7 +3271,8 @@ impl tower_lsp::LanguageServer for LanguageServer { (ls.performance.clone(), mark) }; - if self.refresh_specifiers_from_client().await { + self.refresh_configuration().await; + { let mut ls = self.0.write().await; ls.refresh_documents_config().await; ls.diagnostics_server.invalidate_all(); @@ -3681,10 +3579,7 @@ impl Inner { .normalize_url(¶ms.text_document.uri, LspUrlKind::File); if !self.is_diagnosable(&specifier) || !self.config.specifier_enabled(&specifier) - || !self - .config - .workspace_settings() - .enabled_inlay_hints(&specifier) + || !self.config.enabled_inlay_hints_for_specifier(&specifier) { return Ok(None); } |