summaryrefslogtreecommitdiff
path: root/cli/lsp/language_server.rs
diff options
context:
space:
mode:
authorDavid Sherret <dsherret@users.noreply.github.com>2023-03-15 10:34:23 -0400
committerGitHub <noreply@github.com>2023-03-15 14:34:23 +0000
commit7070b8ed50f13d95d926b19ed7d7ce9fc0d6d4f3 (patch)
tree1cba1972e1b7fcea1706a893984a3be12093cf1c /cli/lsp/language_server.rs
parent2ca160702795bb1b92196a848f7e4814d23ed32c (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.rs566
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(&params.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(&params));
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params));
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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document_position.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document_position.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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,
&params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.item.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.item.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document_position.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document_position_params.text_document.uri);
+ let specifier = self.url_map.normalize_url(
+ &params.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(&params));
-
- 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(&params)),
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(&params));
+ 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(&params.referrer.uri);
+ let referrer = self
+ .url_map
+ .normalize_url(&params.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(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.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(&params));
- let specifier = self.url_map.normalize_url(&params.text_document.uri);
+ let specifier = self
+ .url_map
+ .normalize_url(&params.text_document.uri, LspUrlKind::File);
let contents = if specifier.as_str() == "deno:/status.md" {
let mut contents = String::new();
let mut documents_specifiers = self