diff options
Diffstat (limited to 'cli/lsp/documents.rs')
-rw-r--r-- | cli/lsp/documents.rs | 179 |
1 files changed, 128 insertions, 51 deletions
diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 1282f8a18..1f0487296 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -20,6 +20,7 @@ use crate::npm::CliNpmRegistryApi; use crate::npm::NpmResolution; use crate::npm::PackageJsonDepsInstaller; use crate::resolver::CliGraphResolver; +use crate::util::glob; use crate::util::path::specifier_to_file_path; use crate::util::text_encoding; @@ -1259,7 +1260,20 @@ impl Documents { // only refresh the dependencies if the underlying configuration has changed if self.resolver_config_hash != new_resolver_config_hash { self.refresh_dependencies( - options.enabled_urls, + options + .enabled_urls + .iter() + .filter_map(|url| specifier_to_file_path(url).ok()) + .collect(), + options + .maybe_config_file + .and_then(|cf| { + cf.to_files_config() + .ok() + .flatten() + .map(|files| files.exclude) + }) + .unwrap_or_default(), options.document_preload_limit, ); self.resolver_config_hash = new_resolver_config_hash; @@ -1270,7 +1284,8 @@ impl Documents { fn refresh_dependencies( &mut self, - enabled_urls: Vec<Url>, + enabled_paths: Vec<PathBuf>, + disabled_paths: Vec<PathBuf>, document_preload_limit: usize, ) { let resolver = self.resolver.as_graph_resolver(); @@ -1288,10 +1303,12 @@ impl Documents { let open_docs = &mut self.open_docs; log::debug!("Preloading documents from enabled urls..."); - let mut finder = PreloadDocumentFinder::from_enabled_urls_with_limit( - &enabled_urls, - document_preload_limit, - ); + let mut finder = + PreloadDocumentFinder::new(PreloadDocumentFinderOptions { + enabled_paths, + disabled_paths, + limit: document_preload_limit, + }); for specifier in finder.by_ref() { // mark this document as having been found not_found_docs.remove(&specifier); @@ -1585,19 +1602,41 @@ enum PendingEntry { ReadDir(Box<ReadDir>), } +struct PreloadDocumentFinderOptions { + enabled_paths: Vec<PathBuf>, + disabled_paths: Vec<PathBuf>, + limit: usize, +} + /// Iterator that finds documents that can be preloaded into /// the LSP on startup. struct PreloadDocumentFinder { limit: usize, entry_count: usize, pending_entries: VecDeque<PendingEntry>, + disabled_globs: glob::GlobSet, + disabled_paths: HashSet<PathBuf>, } impl PreloadDocumentFinder { - pub fn from_enabled_urls_with_limit( - enabled_urls: &Vec<Url>, - limit: usize, - ) -> Self { + pub fn new(options: PreloadDocumentFinderOptions) -> Self { + fn paths_into_globs_and_paths( + input_paths: Vec<PathBuf>, + ) -> (glob::GlobSet, HashSet<PathBuf>) { + let mut globs = Vec::with_capacity(input_paths.len()); + let mut paths = HashSet::with_capacity(input_paths.len()); + for path in input_paths { + if let Ok(Some(glob)) = + glob::GlobPattern::new_if_pattern(&path.to_string_lossy()) + { + globs.push(glob); + } else { + paths.insert(path); + } + } + (glob::GlobSet::new(globs), paths) + } + fn is_allowed_root_dir(dir_path: &Path) -> bool { if dir_path.parent().is_none() { // never search the root directory of a drive @@ -1606,23 +1645,27 @@ impl PreloadDocumentFinder { true } + let (disabled_globs, disabled_paths) = + paths_into_globs_and_paths(options.disabled_paths); let mut finder = PreloadDocumentFinder { - limit, + limit: options.limit, entry_count: 0, pending_entries: Default::default(), + disabled_globs, + disabled_paths, }; - let mut dirs = Vec::with_capacity(enabled_urls.len()); - for enabled_url in enabled_urls { - if let Ok(path) = enabled_url.to_file_path() { - if path.is_dir() { - if is_allowed_root_dir(&path) { - dirs.push(path); - } - } else { - finder - .pending_entries - .push_back(PendingEntry::SpecifiedRootFile(path)); + + // initialize the finder with the initial paths + let mut dirs = Vec::with_capacity(options.enabled_paths.len()); + for path in options.enabled_paths { + if path.is_dir() { + if is_allowed_root_dir(&path) { + dirs.push(path); } + } else { + finder + .pending_entries + .push_back(PendingEntry::SpecifiedRootFile(path)); } } for dir in sort_and_remove_non_leaf_dirs(dirs) { @@ -1737,17 +1780,21 @@ impl Iterator for PreloadDocumentFinder { if let Ok(entry) = entry { let path = entry.path(); if let Ok(file_type) = entry.file_type() { - if file_type.is_dir() && is_discoverable_dir(&path) { - self - .pending_entries - .push_back(PendingEntry::Dir(path.to_path_buf())); - } else if file_type.is_file() && is_discoverable_file(&path) { - if let Some(specifier) = Self::get_valid_specifier(&path) { - // restore the next entries for next time + if !self.disabled_paths.contains(&path) + && !self.disabled_globs.matches_path(&path) + { + if file_type.is_dir() && is_discoverable_dir(&path) { self .pending_entries - .push_front(PendingEntry::ReadDir(entries)); - return Some(specifier); + .push_back(PendingEntry::Dir(path.to_path_buf())); + } else if file_type.is_file() && is_discoverable_file(&path) { + if let Some(specifier) = Self::get_valid_specifier(&path) { + // restore the next entries for next time + self + .pending_entries + .push_front(PendingEntry::ReadDir(entries)); + return Some(specifier); + } } } } @@ -2018,23 +2065,28 @@ console.log(b, "hello deno"); temp_dir.write("root1/target/main.ts", ""); // no, because there is a Cargo.toml in the root directory temp_dir.create_dir_all("root2/folder"); + temp_dir.create_dir_all("root2/sub_folder"); temp_dir.write("root2/file1.ts", ""); // yes, provided temp_dir.write("root2/file2.ts", ""); // no, not provided temp_dir.write("root2/main.min.ts", ""); // yes, provided temp_dir.write("root2/folder/main.ts", ""); // yes, provided + temp_dir.write("root2/sub_folder/a.js", ""); // no, not provided + temp_dir.write("root2/sub_folder/b.ts", ""); // no, not provided + temp_dir.write("root2/sub_folder/c.js", ""); // no, not provided temp_dir.create_dir_all("root3/"); temp_dir.write("root3/mod.ts", ""); // no, not provided - let mut urls = PreloadDocumentFinder::from_enabled_urls_with_limit( - &vec![ - temp_dir.uri().join("root1/").unwrap(), - temp_dir.uri().join("root2/file1.ts").unwrap(), - temp_dir.uri().join("root2/main.min.ts").unwrap(), - temp_dir.uri().join("root2/folder/").unwrap(), + let mut urls = PreloadDocumentFinder::new(PreloadDocumentFinderOptions { + enabled_paths: vec![ + temp_dir.path().join("root1"), + temp_dir.path().join("root2").join("file1.ts"), + temp_dir.path().join("root2").join("main.min.ts"), + temp_dir.path().join("root2").join("folder"), ], - 1_000, - ) + disabled_paths: Vec::new(), + limit: 1_000, + }) .collect::<Vec<_>>(); // Ideally we would test for order here, which should be BFS, but @@ -2061,32 +2113,57 @@ console.log(b, "hello deno"); ); // now try iterating with a low limit - let urls = PreloadDocumentFinder::from_enabled_urls_with_limit( - &vec![temp_dir.uri()], - 10, // entries and not results - ) + let urls = PreloadDocumentFinder::new(PreloadDocumentFinderOptions { + enabled_paths: vec![temp_dir.path().to_path_buf()], + disabled_paths: Vec::new(), + limit: 10, // entries and not results + }) .collect::<Vec<_>>(); // since different file system have different iteration // order, the number here may vary, so just assert it's below // a certain amount assert!(urls.len() < 5, "Actual length: {}", urls.len()); + + // now try with certain directories and files disabled + let mut urls = PreloadDocumentFinder::new(PreloadDocumentFinderOptions { + enabled_paths: vec![temp_dir.path().to_path_buf()], + disabled_paths: vec![ + temp_dir.path().to_path_buf().join("root1"), + temp_dir.path().to_path_buf().join("root2").join("file1.ts"), + temp_dir.path().to_path_buf().join("**/*.js"), // ignore js files + ], + limit: 1_000, + }) + .collect::<Vec<_>>(); + urls.sort(); + assert_eq!( + urls, + vec![ + temp_dir.uri().join("root2/file2.ts").unwrap(), + temp_dir.uri().join("root2/folder/main.ts").unwrap(), + temp_dir.uri().join("root2/sub_folder/b.ts").unwrap(), // won't have the javascript files + temp_dir.uri().join("root3/mod.ts").unwrap(), + ] + ); } #[test] pub fn test_pre_load_document_finder_disallowed_dirs() { if cfg!(windows) { - let paths = PreloadDocumentFinder::from_enabled_urls_with_limit( - &vec![Url::parse("file:///c:/").unwrap()], - 1_000, - ) + let paths = PreloadDocumentFinder::new(PreloadDocumentFinderOptions { + enabled_paths: vec![PathBuf::from("C:\\")], + disabled_paths: Vec::new(), + limit: 1_000, + }) .collect::<Vec<_>>(); assert_eq!(paths, vec![]); } else { - let paths = PreloadDocumentFinder::from_enabled_urls_with_limit( - &vec![Url::parse("file:///").unwrap()], - 1_000, - ) + let paths = PreloadDocumentFinder::new(PreloadDocumentFinderOptions { + enabled_paths: vec![PathBuf::from("/")], + disabled_paths: Vec::new(), + limit: 1_000, + }) .collect::<Vec<_>>(); assert_eq!(paths, vec![]); } |