fix(lsp): re-enable the per resource configuration without a deadlock (#10625)

Fixes #10603
This commit is contained in:
Kitson Kelly 2021-05-20 19:56:48 +10:00 committed by GitHub
parent bdee065d42
commit 014d8d51c0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 499 additions and 189 deletions

View file

@ -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(&params.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(&params));
let specifier = self.url_map.normalize_url(&params.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, &params.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(&params));
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(&params.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,
&params.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(&params)
} 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);