diff options
Diffstat (limited to 'cli')
-rw-r--r-- | cli/lsp/config.rs | 126 | ||||
-rw-r--r-- | cli/lsp/documents.rs | 2 | ||||
-rw-r--r-- | cli/lsp/language_server.rs | 32 | ||||
-rw-r--r-- | cli/lsp/tsc.rs | 6 |
4 files changed, 86 insertions, 80 deletions
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index 43b8a5fb7..364999cff 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -31,6 +31,7 @@ use deno_runtime::fs_util::specifier_to_file_path; use deno_runtime::permissions::PermissionsContainer; use import_map::ImportMap; use lsp::Url; +use lsp_types::ClientCapabilities; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::HashMap; @@ -40,21 +41,6 @@ use tower_lsp::lsp_types as lsp; pub const SETTINGS_SECTION: &str = "deno"; -#[derive(Debug, Clone, Default)] -pub struct ClientCapabilities { - pub code_action_disabled_support: bool, - pub line_folding_only: bool, - pub snippet_support: bool, - pub status_notification: bool, - /// The client provides the `experimental.testingApi` capability, which is - /// built around VSCode's testing API. It indicates that the server should - /// send notifications about tests discovered in modules. - pub testing_api: bool, - pub workspace_configuration: bool, - pub workspace_did_change_watched_files: bool, - pub workspace_will_rename_files: bool, -} - fn is_true() -> bool { true } @@ -975,57 +961,73 @@ impl Config { &self.settings.unscoped.internal_inspect } - pub fn update_capabilities( + pub fn set_client_capabilities( &mut self, - capabilities: &lsp::ClientCapabilities, + client_capabilities: ClientCapabilities, ) { - if let Some(experimental) = &capabilities.experimental { - self.client_capabilities.status_notification = experimental - .get("statusNotification") - .and_then(|it| it.as_bool()) - == Some(true); - self.client_capabilities.testing_api = - experimental.get("testingApi").and_then(|it| it.as_bool()) - == Some(true); - } + self.client_capabilities = client_capabilities; + } - if let Some(workspace) = &capabilities.workspace { - self.client_capabilities.workspace_configuration = - workspace.configuration.unwrap_or(false); - self.client_capabilities.workspace_did_change_watched_files = workspace - .did_change_watched_files - .and_then(|it| it.dynamic_registration) - .unwrap_or(false); - if let Some(file_operations) = &workspace.file_operations { - if let Some(true) = file_operations.dynamic_registration { - self.client_capabilities.workspace_will_rename_files = - file_operations.will_rename.unwrap_or(false); - } - } - } + pub fn workspace_capable(&self) -> bool { + self.client_capabilities.workspace.is_some() + } - if let Some(text_document) = &capabilities.text_document { - self.client_capabilities.line_folding_only = text_document - .folding_range - .as_ref() - .and_then(|it| it.line_folding_only) - .unwrap_or(false); - self.client_capabilities.code_action_disabled_support = text_document - .code_action - .as_ref() - .and_then(|it| it.disabled_support) - .unwrap_or(false); - self.client_capabilities.snippet_support = - if let Some(completion) = &text_document.completion { - completion - .completion_item - .as_ref() - .and_then(|it| it.snippet_support) - .unwrap_or(false) - } else { - false - }; - } + pub fn workspace_configuration_capable(&self) -> bool { + (|| self.client_capabilities.workspace.as_ref()?.configuration)() + .unwrap_or(false) + } + + pub fn did_change_watched_files_capable(&self) -> bool { + (|| { + let workspace = self.client_capabilities.workspace.as_ref()?; + let did_change_watched_files = + workspace.did_change_watched_files.as_ref()?; + did_change_watched_files.dynamic_registration + })() + .unwrap_or(false) + } + + pub fn will_rename_files_capable(&self) -> bool { + (|| { + let workspace = self.client_capabilities.workspace.as_ref()?; + let file_operations = workspace.file_operations.as_ref()?; + file_operations.dynamic_registration.filter(|d| *d)?; + file_operations.will_rename + })() + .unwrap_or(false) + } + + pub fn line_folding_only_capable(&self) -> bool { + (|| { + let text_document = self.client_capabilities.text_document.as_ref()?; + text_document.folding_range.as_ref()?.line_folding_only + })() + .unwrap_or(false) + } + + pub fn code_action_disabled_capable(&self) -> bool { + (|| { + let text_document = self.client_capabilities.text_document.as_ref()?; + text_document.code_action.as_ref()?.disabled_support + })() + .unwrap_or(false) + } + + pub fn snippet_support_capable(&self) -> bool { + (|| { + let text_document = self.client_capabilities.text_document.as_ref()?; + let completion = text_document.completion.as_ref()?; + completion.completion_item.as_ref()?.snippet_support + })() + .unwrap_or(false) + } + + pub fn testing_api_capable(&self) -> bool { + (|| { + let experimental = self.client_capabilities.experimental.as_ref()?; + experimental.get("testingApi")?.as_bool() + })() + .unwrap_or(false) } } diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 5a94daed7..7cf839a69 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -226,7 +226,7 @@ fn get_maybe_test_module_fut( maybe_parsed_source: Option<&ParsedSourceResult>, config: &Config, ) -> Option<TestModuleFut> { - if !config.client_capabilities.testing_api { + if !config.testing_api_capable() { return None; } let parsed_source = maybe_parsed_source?.as_ref().ok()?.clone(); diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index 5f79bca32..f0f730946 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -439,7 +439,7 @@ impl LanguageServer { ( inner.client.clone(), inner.config.workspace_folders.clone(), - inner.config.client_capabilities.workspace_configuration, + inner.config.workspace_configuration_capable(), ) }; if capable { @@ -769,7 +769,7 @@ impl Inner { vec![], ); } - self.config.update_capabilities(¶ms.capabilities); + self.config.set_client_capabilities(params.capabilities); } self.diagnostics_server.start(); @@ -802,6 +802,10 @@ impl Inner { } fn walk_workspace(config: &Config) -> (BTreeSet<ModuleSpecifier>, bool) { + if !config.workspace_capable() { + log::debug!("Skipped workspace walk due to client incapability."); + return (Default::default(), false); + } let mut workspace_files = Default::default(); let entry_limit = 1000; let mut pending = VecDeque::new(); @@ -1664,10 +1668,10 @@ impl Inner { .map(CodeActionOrCommand::CodeAction), ); - let code_action_disabled_support = - self.config.client_capabilities.code_action_disabled_support; + let code_action_disabled_capable = + self.config.code_action_disabled_capable(); let actions: Vec<CodeActionOrCommand> = all_actions.into_iter().filter(|ca| { - code_action_disabled_support + code_action_disabled_capable || matches!(ca, CodeActionOrCommand::CodeAction(ca) if ca.disabled.is_none()) }).collect(); let response = if actions.is_empty() { @@ -2318,7 +2322,7 @@ impl Inner { span.to_folding_range( asset_or_doc.line_index(), asset_or_doc.text().as_bytes(), - self.config.client_capabilities.line_folding_only, + self.config.line_folding_only_capable(), ) }) .collect::<Vec<FoldingRange>>(), @@ -2887,11 +2891,7 @@ impl tower_lsp::LanguageServer for LanguageServer { inner.refresh_documents_config().await; inner.task_queue.start(self.clone()); self.init_flag.raise(); - if inner - .config - .client_capabilities - .workspace_did_change_watched_files - { + if inner.config.did_change_watched_files_capable() { // 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. @@ -2909,7 +2909,7 @@ impl tower_lsp::LanguageServer for LanguageServer { register_options: Some(serde_json::to_value(options).unwrap()), }); } - if inner.config.client_capabilities.workspace_will_rename_files { + if inner.config.will_rename_files_capable() { let options = FileOperationRegistrationOptions { filters: vec![FileOperationFilter { scheme: Some("file".to_string()), @@ -2927,7 +2927,7 @@ impl tower_lsp::LanguageServer for LanguageServer { }); } - if inner.config.client_capabilities.testing_api { + if inner.config.testing_api_capable() { let test_server = testing::TestServer::new( inner.client.clone(), inner.performance.clone(), @@ -3051,7 +3051,7 @@ impl tower_lsp::LanguageServer for LanguageServer { }; self.refresh_configuration().await; let mut inner = self.inner.write().await; - if !inner.config.client_capabilities.workspace_configuration { + if !inner.config.workspace_configuration_capable() { let config = params.settings.as_object().map(|settings| { let deno = serde_json::to_value(settings.get(SETTINGS_SECTION)).unwrap(); @@ -3726,6 +3726,10 @@ mod tests { temp_dir.uri().join("root2/").unwrap(), temp_dir.uri().join("root3/").unwrap(), ]); + config.set_client_capabilities(ClientCapabilities { + workspace: Some(Default::default()), + ..Default::default() + }); config.set_workspace_settings( Default::default(), vec![ diff --git a/cli/lsp/tsc.rs b/cli/lsp/tsc.rs index ebd3fc973..76a33a532 100644 --- a/cli/lsp/tsc.rs +++ b/cli/lsp/tsc.rs @@ -4679,7 +4679,7 @@ impl UserPreferences { // TODO(nayeemrmn): Investigate why we use `Index` here. import_module_specifier_ending: Some(ImportModuleSpecifierEnding::Index), include_completions_with_snippet_text: Some( - config.client_capabilities.snippet_support, + config.snippet_support_capable(), ), provide_refactor_not_applicable_reason: Some(true), quote_preference: Some(fmt_config.into()), @@ -4717,7 +4717,7 @@ impl UserPreferences { include_completions_with_class_member_snippets: Some( language_settings.suggest.enabled && language_settings.suggest.class_member_snippets.enabled - && config.client_capabilities.snippet_support, + && config.snippet_support_capable(), ), include_completions_with_insert_text: Some( language_settings.suggest.enabled, @@ -4728,7 +4728,7 @@ impl UserPreferences { .suggest .object_literal_method_snippets .enabled - && config.client_capabilities.snippet_support, + && config.snippet_support_capable(), ), import_module_specifier_preference: Some( language_settings.preferences.import_module_specifier, |