From c0dcf6a3571ee04b4826c52d1329804e7c2b02c4 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Thu, 31 Aug 2023 19:10:09 +0100 Subject: [PATCH] feat(lsp): enable via config file detection (#20334) With https://github.com/denoland/vscode_deno/pull/902 for https://github.com/denoland/vscode_deno/issues/880. For multi-folder workspaces, note that this only scans the first one and applies the result to all. That means users would have to still have to specify `"deno.enable": true/false` for their secondary folders if the preference is different for those. --- cli/lsp/client.rs | 2 +- cli/lsp/config.rs | 53 ++++++++++++++++++++++++++++++-------- cli/lsp/diagnostics.rs | 4 +-- cli/lsp/language_server.rs | 2 +- cli/lsp/repl.rs | 2 +- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/cli/lsp/client.rs b/cli/lsp/client.rs index 45fc88376d..acef59f97d 100644 --- a/cli/lsp/client.rs +++ b/cli/lsp/client.rs @@ -359,7 +359,7 @@ impl ClientTrait for ReplClient { .into_iter() .map(|_| { Ok(SpecifierSettings { - enable: true, + enable: Some(true), ..Default::default() }) }) diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index 292f07e474..b70af65197 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -236,7 +236,7 @@ impl Default for ImportCompletionSettings { #[serde(rename_all = "camelCase")] pub struct SpecifierSettings { /// A flag that indicates if Deno is enabled for this specifier or not. - pub enable: bool, + pub enable: Option, /// A list of paths, using the workspace folder as a base that should be Deno /// enabled. #[serde(default)] @@ -288,8 +288,7 @@ fn empty_string_none<'de, D: serde::Deserializer<'de>>( #[serde(rename_all = "camelCase")] pub struct WorkspaceSettings { /// A flag that indicates if Deno is enabled for the workspace. - #[serde(default)] - pub enable: bool, + pub enable: Option, /// A list of paths, using the root_uri as a base that should be Deno enabled. #[serde(default)] @@ -359,7 +358,7 @@ pub struct WorkspaceSettings { impl Default for WorkspaceSettings { fn default() -> Self { WorkspaceSettings { - enable: false, + enable: None, enable_paths: vec![], cache: None, certificate_stores: None, @@ -405,6 +404,7 @@ pub struct ConfigSnapshot { pub client_capabilities: ClientCapabilities, pub enabled_paths: HashMap>, pub excluded_paths: Option>, + pub has_config_file: bool, pub settings: Settings, } @@ -415,6 +415,7 @@ impl ConfigSnapshot { &self.enabled_paths, self.excluded_paths.as_ref(), &self.settings, + self.has_config_file, specifier, ) } @@ -523,6 +524,10 @@ impl Config { self.maybe_config_file_info = None; } + pub fn has_config_file(&self) -> bool { + self.maybe_config_file_info.is_some() + } + pub fn set_config_file(&mut self, config_file: ConfigFile) { self.maybe_config_file_info = Some(LspConfigFileInfo { maybe_lockfile: resolve_lockfile_from_config(&config_file).map( @@ -582,6 +587,7 @@ impl Config { .maybe_config_file_info .as_ref() .map(|i| i.excluded_paths.clone()), + has_config_file: self.has_config_file(), settings: self.settings.clone(), }) } @@ -590,6 +596,14 @@ impl Config { self.settings.specifiers.contains_key(specifier) } + pub fn enabled(&self) -> bool { + self + .settings + .workspace + .enable + .unwrap_or_else(|| self.has_config_file()) + } + pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool { specifier_enabled( &self.enabled_paths, @@ -598,6 +612,7 @@ impl Config { .as_ref() .map(|i| &i.excluded_paths), &self.settings, + self.has_config_file(), specifier, ) } @@ -610,7 +625,7 @@ impl Config { pub fn enabled_urls(&self) -> Vec { let mut urls: Vec = Vec::new(); - if !self.settings.workspace.enable && self.enabled_paths.is_empty() { + if !self.enabled() && self.enabled_paths.is_empty() { // do not return any urls when disabled return urls; } @@ -780,6 +795,7 @@ fn specifier_enabled( enabled_paths: &HashMap>, excluded_paths: Option<&Vec>, settings: &Settings, + workspace_has_config_file: bool, specifier: &Url, ) -> bool { let specifier_str = specifier.as_str(); @@ -800,8 +816,9 @@ fn specifier_enabled( settings .specifiers .get(specifier) - .map(|settings| settings.enable) - .unwrap_or_else(|| settings.workspace.enable) + .and_then(|settings| settings.enable) + .or(settings.workspace.enable) + .unwrap_or(workspace_has_config_file) } fn resolve_lockfile_from_config(config_file: &ConfigFile) -> Option { @@ -916,7 +933,7 @@ mod tests { assert_eq!( config.workspace_settings().clone(), WorkspaceSettings { - enable: false, + enable: None, enable_paths: Vec::new(), cache: None, certificate_stores: None, @@ -1025,14 +1042,14 @@ mod tests { let mut config = Config::new(); let root_dir = Url::parse("file:///example/").unwrap(); config.root_uri = Some(root_dir.clone()); - config.settings.workspace.enable = false; + config.settings.workspace.enable = Some(false); config.settings.workspace.enable_paths = Vec::new(); assert_eq!(config.enabled_urls(), vec![]); - config.settings.workspace.enable = true; + config.settings.workspace.enable = Some(true); assert_eq!(config.enabled_urls(), vec![root_dir]); - config.settings.workspace.enable = false; + config.settings.workspace.enable = Some(false); let root_dir1 = Url::parse("file:///root1/").unwrap(); let root_dir2 = Url::parse("file:///root2/").unwrap(); let root_dir3 = Url::parse("file:///root3/").unwrap(); @@ -1060,4 +1077,18 @@ mod tests { ] ); } + + #[test] + fn config_enable_via_config_file_detection() { + let mut config = Config::new(); + let root_uri = Url::parse("file:///root/").unwrap(); + config.root_uri = Some(root_uri.clone()); + config.settings.workspace.enable = None; + assert_eq!(config.enabled_urls(), vec![]); + + config.set_config_file( + ConfigFile::new("{}", root_uri.join("deno.json").unwrap()).unwrap(), + ); + assert_eq!(config.enabled_urls(), vec![root_uri]); + } } diff --git a/cli/lsp/diagnostics.rs b/cli/lsp/diagnostics.rs index dea43ad87a..f2f45a9285 100644 --- a/cli/lsp/diagnostics.rs +++ b/cli/lsp/diagnostics.rs @@ -1390,7 +1390,7 @@ mod tests { ConfigSnapshot { settings: Settings { workspace: WorkspaceSettings { - enable: true, + enable: Some(true), lint: true, ..Default::default() }, @@ -1466,7 +1466,7 @@ let c: number = "a"; disabled_config.settings.specifiers.insert( specifier.clone(), SpecifierSettings { - enable: false, + enable: Some(false), enable_paths: Vec::new(), code_lens: Default::default(), }, diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index d3c7ea492b..dc85eb1cc6 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -3053,7 +3053,7 @@ impl tower_lsp::LanguageServer for LanguageServer { let options = DidChangeWatchedFilesRegistrationOptions { watchers: vec![FileSystemWatcher { glob_pattern: "**/*.{json,jsonc,lock}".to_string(), - kind: Some(WatchKind::Change), + kind: None, }], }; registrations.push(Registration { diff --git a/cli/lsp/repl.rs b/cli/lsp/repl.rs index ad0171629f..598674fdc1 100644 --- a/cli/lsp/repl.rs +++ b/cli/lsp/repl.rs @@ -284,7 +284,7 @@ fn get_cwd_uri() -> Result { pub fn get_repl_workspace_settings() -> WorkspaceSettings { WorkspaceSettings { - enable: true, + enable: Some(true), enable_paths: Vec::new(), config: None, certificate_stores: None,