diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2023-07-10 21:03:19 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-10 21:03:19 -0400 |
commit | 0d8af65621be63a95d57611796a042e5ecf90f85 (patch) | |
tree | 38d5ffc95c33a7166e89a69938f7a053fcbab3af | |
parent | 96efe3c17628e1b77caa752e6de4654a786f4a8d (diff) |
fix(lsp): exclude files in deno.json "exclude" (#19791)
Closes #19788
-rw-r--r-- | cli/lsp/config.rs | 95 | ||||
-rw-r--r-- | cli/tests/integration/lsp_tests.rs | 131 |
2 files changed, 192 insertions, 34 deletions
diff --git a/cli/lsp/config.rs b/cli/lsp/config.rs index 4d008a290..298c86a55 100644 --- a/cli/lsp/config.rs +++ b/cli/lsp/config.rs @@ -403,27 +403,19 @@ impl WorkspaceSettings { pub struct ConfigSnapshot { pub client_capabilities: ClientCapabilities, pub enabled_paths: HashMap<Url, Vec<Url>>, + pub excluded_paths: Option<Vec<Url>>, pub settings: Settings, } impl ConfigSnapshot { /// Determine if the provided specifier is enabled or not. pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool { - if !self.enabled_paths.is_empty() { - let specifier_str = specifier.as_str(); - for (workspace, enabled_paths) in self.enabled_paths.iter() { - if specifier_str.starts_with(workspace.as_str()) { - return enabled_paths - .iter() - .any(|path| specifier_str.starts_with(path.as_str())); - } - } - } - if let Some(settings) = self.settings.specifiers.get(specifier) { - settings.enable - } else { - self.settings.workspace.enable - } + specifier_enabled( + &self.enabled_paths, + self.excluded_paths.as_ref(), + &self.settings, + specifier, + ) } } @@ -436,11 +428,12 @@ pub struct Settings { /// Contains the config file and dependent information. #[derive(Debug)] struct LspConfigFileInfo { - pub config_file: ConfigFile, + config_file: ConfigFile, /// An optional deno.lock file, which is resolved relative to the config file. - pub maybe_lockfile: Option<Arc<Mutex<Lockfile>>>, + maybe_lockfile: Option<Arc<Mutex<Lockfile>>>, /// The canonicalized node_modules directory, which is found relative to the config file. - pub maybe_node_modules_dir: Option<PathBuf>, + maybe_node_modules_dir: Option<PathBuf>, + excluded_paths: Vec<Url>, } #[derive(Debug)] @@ -494,6 +487,15 @@ impl Config { self.maybe_config_file_info = Some(LspConfigFileInfo { maybe_lockfile: resolve_lockfile_from_config(&config_file), maybe_node_modules_dir: resolve_node_modules_dir(&config_file), + excluded_paths: config_file + .to_files_config() + .ok() + .flatten() + .map(|c| c.exclude) + .unwrap_or_default() + .into_iter() + .filter_map(|path| ModuleSpecifier::from_file_path(path).ok()) + .collect(), config_file, }); } @@ -517,6 +519,10 @@ impl Config { Arc::new(ConfigSnapshot { client_capabilities: self.client_capabilities.clone(), enabled_paths: self.enabled_paths.clone(), + excluded_paths: self + .maybe_config_file_info + .as_ref() + .map(|i| i.excluded_paths.clone()), settings: self.settings.clone(), }) } @@ -526,22 +532,15 @@ impl Config { } pub fn specifier_enabled(&self, specifier: &ModuleSpecifier) -> bool { - if !self.enabled_paths.is_empty() { - let specifier_str = specifier.as_str(); - for (workspace, enabled_paths) in self.enabled_paths.iter() { - if specifier_str.starts_with(workspace.as_str()) { - return enabled_paths - .iter() - .any(|path| specifier_str.starts_with(path.as_str())); - } - } - } - self - .settings - .specifiers - .get(specifier) - .map(|settings| settings.enable) - .unwrap_or_else(|| self.settings.workspace.enable) + specifier_enabled( + &self.enabled_paths, + self + .maybe_config_file_info + .as_ref() + .map(|i| &i.excluded_paths), + &self.settings, + specifier, + ) } /// Gets the directories or specifically enabled file paths based on the @@ -712,6 +711,34 @@ impl Config { } } +fn specifier_enabled( + enabled_paths: &HashMap<Url, Vec<Url>>, + excluded_paths: Option<&Vec<Url>>, + settings: &Settings, + specifier: &Url, +) -> bool { + let specifier_str = specifier.as_str(); + for (workspace, enabled_paths) in enabled_paths.iter() { + if specifier_str.starts_with(workspace.as_str()) { + return enabled_paths + .iter() + .any(|path| specifier_str.starts_with(path.as_str())); + } + } + if let Some(excluded_paths) = excluded_paths { + for excluded_path in excluded_paths { + if specifier_str.starts_with(excluded_path.as_str()) { + return false; + } + } + } + settings + .specifiers + .get(specifier) + .map(|settings| settings.enable) + .unwrap_or_else(|| settings.workspace.enable) +} + fn resolve_lockfile_from_config( config_file: &ConfigFile, ) -> Option<Arc<Mutex<Lockfile>>> { diff --git a/cli/tests/integration/lsp_tests.rs b/cli/tests/integration/lsp_tests.rs index 467fa85a5..eb5885529 100644 --- a/cli/tests/integration/lsp_tests.rs +++ b/cli/tests/integration/lsp_tests.rs @@ -1213,6 +1213,137 @@ fn lsp_workspace_enable_paths() { } #[test] +fn lsp_exclude_config() { + let context = TestContextBuilder::new().use_temp_cwd().build(); + let temp_dir = context.temp_dir(); + temp_dir.create_dir_all("other"); + temp_dir.write( + "other/shared.ts", + // this should not be found in the "find references" since this file is excluded + "import { a } from '../worker/shared.ts'; console.log(a);", + ); + temp_dir.create_dir_all("worker"); + temp_dir.write("worker/shared.ts", "export const a = 1"); + temp_dir.write( + "deno.json", + r#"{ + "exclude": ["other"], +}"#, + ); + let root_specifier = temp_dir.uri(); + + let mut client = context.new_lsp_command().build(); + client.initialize_default(); + + client.did_open(json!({ + "textDocument": { + "uri": root_specifier.join("./other/file.ts").unwrap(), + "languageId": "typescript", + "version": 1, + "text": "console.log(Date.now());\n" + } + })); + + client.did_open(json!({ + "textDocument": { + "uri": root_specifier.join("./worker/file.ts").unwrap(), + "languageId": "typescript", + "version": 1, + "text": concat!( + "console.log(Date.now());\n", + "import { a } from './shared.ts';\n", + "a;\n", + ), + } + })); + + client.did_open(json!({ + "textDocument": { + "uri": root_specifier.join("./worker/subdir/file.ts").unwrap(), + "languageId": "typescript", + "version": 1, + "text": "console.log(Date.now());\n" + } + })); + + let res = client.write_request( + "textDocument/hover", + json!({ + "textDocument": { + "uri": root_specifier.join("./other/file.ts").unwrap(), + }, + "position": { "line": 0, "character": 19 } + }), + ); + assert_eq!(res, json!(null)); + + let res = client.write_request( + "textDocument/hover", + json!({ + "textDocument": { + "uri": root_specifier.join("./worker/file.ts").unwrap(), + }, + "position": { "line": 0, "character": 19 } + }), + ); + assert_eq!( + res, + json!({ + "contents": [ + { + "language": "typescript", + "value": "(method) DateConstructor.now(): number", + }, + "Returns the number of milliseconds elapsed since midnight, January 1, 1970 Universal Coordinated Time (UTC)." + ], + "range": { + "start": { "line": 0, "character": 17, }, + "end": { "line": 0, "character": 20, } + } + }) + ); + + // check that the file system documents were auto-discovered + let res = client.write_request( + "textDocument/references", + json!({ + "textDocument": { + "uri": root_specifier.join("./worker/file.ts").unwrap(), + }, + "position": { "line": 2, "character": 0 }, + "context": { + "includeDeclaration": true + } + }), + ); + + assert_eq!( + res, + json!([{ + "uri": root_specifier.join("./worker/file.ts").unwrap(), + "range": { + "start": { "line": 1, "character": 9 }, + "end": { "line": 1, "character": 10 } + } + }, { + "uri": root_specifier.join("./worker/file.ts").unwrap(), + "range": { + "start": { "line": 2, "character": 0 }, + "end": { "line": 2, "character": 1 } + } + }, { + "uri": root_specifier.join("./worker/shared.ts").unwrap(), + "range": { + "start": { "line": 0, "character": 13 }, + "end": { "line": 0, "character": 14 } + } + }]) + ); + + client.shutdown(); +} + +#[test] fn lsp_hover_unstable_disabled() { let context = TestContextBuilder::new().use_temp_cwd().build(); let mut client = context.new_lsp_command().build(); |