diff options
Diffstat (limited to 'cli/lsp/language_server.rs')
-rw-r--r-- | cli/lsp/language_server.rs | 120 |
1 files changed, 102 insertions, 18 deletions
diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 485eef938..2a36708fb 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -20,6 +20,7 @@ use deno_runtime::deno_node::PackageJson; use deno_runtime::deno_tls::rustls::RootCertStore; use deno_runtime::deno_tls::RootCertStoreProvider; use import_map::ImportMap; +use indexmap::IndexSet; use log::error; use serde_json::from_value; use std::collections::HashMap; @@ -64,6 +65,7 @@ use super::documents::UpdateDocumentConfigOptions; use super::logging::lsp_log; use super::logging::lsp_warn; use super::lsp_custom; +use super::lsp_custom::TaskDefinition; use super::npm::CliNpmSearchApi; use super::parent_process_checker; use super::performance::Performance; @@ -343,8 +345,8 @@ impl LanguageServer { self.0.write().await.reload_import_registries().await } - pub async fn task_request(&self) -> LspResult<Option<Value>> { - self.0.read().await.get_tasks() + pub async fn task_definitions(&self) -> LspResult<Vec<TaskDefinition>> { + self.0.read().await.task_definitions() } pub async fn test_run_request( @@ -1457,7 +1459,7 @@ impl Inner { } } - fn has_config_changed(config: &Config, changes: &HashSet<Url>) -> bool { + fn has_config_changed(config: &Config, changes: &IndexSet<Url>) -> bool { // Check the canonicalized specifier here because file watcher // changes will be for the canonicalized path in vscode, but also check the // non-canonicalized specifier in order to please the tests and handle @@ -1508,31 +1510,91 @@ impl Inner { .performance .mark("did_change_watched_files", Some(¶ms)); let mut touched = false; - let changes: HashSet<Url> = params + let changes: IndexSet<Url> = params .changes .iter() .map(|f| self.url_map.normalize_url(&f.uri, LspUrlKind::File)) .collect(); + let mut config_changes = IndexSet::with_capacity(changes.len()); + // if the current deno.json has changed, we need to reload it if has_config_changed(&self.config, &changes) { + // Check the 'current' config specifier from both before and after it's + // updated. Check canonicalized and uncanonicalized variants for each. + // If any are included in `changes`, send our custom notification for + // `deno.json` changes: `deno/didChangeDenoConfigurationNotification`. + let mut files_to_check = IndexSet::with_capacity(4); + // Collect previous config specifiers. + if let Some(url) = self.config.maybe_config_file().map(|c| &c.specifier) { + files_to_check.insert(url.clone()); + } + if let Some(url) = self.config.maybe_config_file_canonicalized_specifier() + { + files_to_check.insert(url.clone()); + } + // Update config. if let Err(err) = self.update_config_file().await { self.client.show_message(MessageType::WARNING, err); } + // Collect new config specifiers. + if let Some(url) = self.config.maybe_config_file().map(|c| &c.specifier) { + files_to_check.insert(url.clone()); + } + if let Some(url) = self.config.maybe_config_file_canonicalized_specifier() + { + files_to_check.insert(url.clone()); + } + config_changes.extend( + params + .changes + .iter() + .filter(|e| files_to_check.contains(&e.uri)) + .map(|e| lsp_custom::DenoConfigurationChangeEvent { + file_event: e.clone(), + configuration_type: lsp_custom::DenoConfigurationType::DenoJson, + }), + ); if let Err(err) = self.update_tsconfig().await { self.client.show_message(MessageType::WARNING, err); } touched = true; } - if let Some(package_json) = &self.maybe_package_json { - // 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); - } - touched = true; + let has_package_json_changed = changes + .iter() + .any(|e| e.as_str().ends_with("/package.json")); + + if has_package_json_changed { + let mut files_to_check = IndexSet::with_capacity(2); + if let Some(package_json) = &self.maybe_package_json { + files_to_check.insert(package_json.specifier()); + } + if let Err(err) = self.update_package_json() { + self.client.show_message(MessageType::WARNING, err); } + if let Some(package_json) = &self.maybe_package_json { + files_to_check.insert(package_json.specifier()); + } + config_changes.extend( + params + .changes + .iter() + .filter(|e| files_to_check.contains(&e.uri)) + .map(|e| lsp_custom::DenoConfigurationChangeEvent { + file_event: e.clone(), + configuration_type: lsp_custom::DenoConfigurationType::PackageJson, + }), + ); + touched = true; + } + + if !config_changes.is_empty() { + self.client.send_did_change_deno_configuration_notification( + lsp_custom::DidChangeDenoConfigurationNotificationParams { + changes: config_changes.into_iter().collect(), + }, + ); } // if the current import map, or config file has changed, we need to @@ -3580,13 +3642,35 @@ impl Inner { json!({ "averages": averages }) } - fn get_tasks(&self) -> LspResult<Option<Value>> { - Ok( - self - .config - .maybe_config_file() - .and_then(|cf| cf.to_lsp_tasks()), - ) + fn task_definitions(&self) -> LspResult<Vec<TaskDefinition>> { + let mut result = vec![]; + if let Some(config_file) = self.config.maybe_config_file() { + if let Some(tasks) = json!(&config_file.json.tasks).as_object() { + for (name, value) in tasks { + let Some(command) = value.as_str() else { + continue; + }; + result.push(TaskDefinition { + name: name.clone(), + command: command.to_string(), + source_uri: config_file.specifier.clone(), + }); + } + }; + } + if let Some(package_json) = &self.maybe_package_json { + if let Some(scripts) = &package_json.scripts { + for (name, command) in scripts { + result.push(TaskDefinition { + name: name.clone(), + command: command.clone(), + source_uri: package_json.specifier(), + }); + } + } + } + result.sort_by_key(|d| d.name.clone()); + Ok(result) } async fn inlay_hint( |