diff --git a/Cargo.lock b/Cargo.lock index d339ac32568c9f3ff3ee5941907ac41ac4409027..3ae96f4751751fb06ce6250a31b138f93cd4cdf0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2038,7 +2038,6 @@ dependencies = [ "futures 0.3.28", "fuzzy", "git", - "glob", "gpui", "indoc", "itertools", @@ -3442,7 +3441,7 @@ dependencies = [ "futures 0.3.28", "fuzzy", "git", - "glob", + "globset", "gpui", "indoc", "lazy_static", @@ -4851,7 +4850,7 @@ dependencies = [ "fuzzy", "git", "git2", - "glob", + "globset", "gpui", "ignore", "itertools", @@ -5949,7 +5948,7 @@ dependencies = [ "collections", "editor", "futures 0.3.28", - "glob", + "globset", "gpui", "language", "log", @@ -6111,7 +6110,6 @@ dependencies = [ "collections", "fs", "futures 0.3.28", - "glob", "gpui", "json_comments", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index f14e1c73552f766034ee1d98dd1a51fe3a00bf09..4854be0c7bb1985770f699395a88fc1d3b89d9b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,7 +77,7 @@ async-trait = { version = "0.1" } ctor = { version = "0.1" } env_logger = { version = "0.9" } futures = { version = "0.3" } -glob = { version = "0.3.1" } +globset = { version = "0.4" } lazy_static = { version = "1.4.0" } log = { version = "0.4.16", features = ["kv_unstable_serde"] } ordered-float = { version = "2.1.1" } diff --git a/crates/copilot_button/src/copilot_button.rs b/crates/copilot_button/src/copilot_button.rs index 73cd8f6a1d8ae4cbec8fe89b53d912a25026e759..fdd0da19700a408cc992f9f0d911112c036ebbbd 100644 --- a/crates/copilot_button/src/copilot_button.rs +++ b/crates/copilot_button/src/copilot_button.rs @@ -335,10 +335,9 @@ async fn configure_disabled_globs( .get::(None) .copilot .disabled_globs - .clone() .iter() - .map(|glob| glob.as_str().to_string()) - .collect::>() + .map(|glob| glob.glob().to_string()) + .collect() }); if let Some(path_to_disable) = &path_to_disable { diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index fc7bf4b8abad6732ab338e439db6f30ba2f49e83..325883b7c03fcbc8ed4d2c33df7f4ff00d4e3ef2 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -49,7 +49,6 @@ workspace = { path = "../workspace" } aho-corasick = "0.7" anyhow.workspace = true futures.workspace = true -glob.workspace = true indoc = "1.0.4" itertools = "0.10" lazy_static.workspace = true @@ -82,7 +81,6 @@ workspace = { path = "../workspace", features = ["test-support"] } ctor.workspace = true env_logger.workspace = true -glob.workspace = true rand.workspace = true unindent.workspace = true tree-sitter = "0.20" diff --git a/crates/language/Cargo.toml b/crates/language/Cargo.toml index 5a7644d98e6220d77bda66bcd6d6f35f895b67a6..7e81620e5cea9fc86e207394745aeadfd80982e4 100644 --- a/crates/language/Cargo.toml +++ b/crates/language/Cargo.toml @@ -41,7 +41,7 @@ anyhow.workspace = true async-broadcast = "0.4" async-trait.workspace = true futures.workspace = true -glob.workspace = true +globset.workspace = true lazy_static.workspace = true log.workspace = true parking_lot.workspace = true diff --git a/crates/language/src/language_settings.rs b/crates/language/src/language_settings.rs index b47982819a5a59dbc79791c04ec4918c7f99a00a..d877304f1d991eeb22a58022f6c9723be71ba1cd 100644 --- a/crates/language/src/language_settings.rs +++ b/crates/language/src/language_settings.rs @@ -1,5 +1,6 @@ use anyhow::Result; use collections::HashMap; +use globset::GlobMatcher; use gpui::AppContext; use schemars::{ schema::{InstanceType, ObjectValidation, Schema, SchemaObject}, @@ -45,7 +46,7 @@ pub struct LanguageSettings { #[derive(Clone, Debug, Default)] pub struct CopilotSettings { pub feature_enabled: bool, - pub disabled_globs: Vec, + pub disabled_globs: Vec, } #[derive(Clone, Serialize, Deserialize, JsonSchema)] @@ -151,7 +152,7 @@ impl AllLanguageSettings { .copilot .disabled_globs .iter() - .any(|glob| glob.matches_path(path)) + .any(|glob| glob.is_match(path)) } pub fn copilot_enabled(&self, language_name: Option<&str>, path: Option<&Path>) -> bool { @@ -236,7 +237,7 @@ impl settings::Setting for AllLanguageSettings { feature_enabled: copilot_enabled, disabled_globs: copilot_globs .iter() - .filter_map(|pattern| glob::Pattern::new(pattern).ok()) + .filter_map(|g| Some(globset::Glob::new(g).ok()?.compile_matcher())) .collect(), }, defaults, diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index 190f1d96a8539ad41e224f346be35957547f570f..d6578c87ba6232461750de71091383618164f48e 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -42,7 +42,7 @@ anyhow.workspace = true async-trait.workspace = true backtrace = "0.3" futures.workspace = true -glob.workspace = true +globset.workspace = true ignore = "0.4" lazy_static.workspace = true log.workspace = true diff --git a/crates/project/src/lsp_glob_set.rs b/crates/project/src/lsp_glob_set.rs deleted file mode 100644 index daac344a0a8fb4396da802ddc6f7325ffd47ea9f..0000000000000000000000000000000000000000 --- a/crates/project/src/lsp_glob_set.rs +++ /dev/null @@ -1,121 +0,0 @@ -use anyhow::{anyhow, Result}; -use std::path::Path; - -#[derive(Default)] -pub struct LspGlobSet { - patterns: Vec, -} - -impl LspGlobSet { - pub fn clear(&mut self) { - self.patterns.clear(); - } - - /// Add a pattern to the glob set. - /// - /// LSP's glob syntax supports bash-style brace expansion. For example, - /// the pattern '*.{js,ts}' would match all JavaScript or TypeScript files. - /// This is not a part of the standard libc glob syntax, and isn't supported - /// by the `glob` crate. So we pre-process the glob patterns, producing a - /// separate glob `Pattern` object for each part of a brace expansion. - pub fn add_pattern(&mut self, pattern: &str) -> Result<()> { - // Find all of the ranges of `pattern` that contain matched curly braces. - let mut expansion_ranges = Vec::new(); - let mut expansion_start_ix = None; - for (ix, c) in pattern.match_indices(|c| ['{', '}'].contains(&c)) { - match c { - "{" => { - if expansion_start_ix.is_some() { - return Err(anyhow!("nested braces in glob patterns aren't supported")); - } - expansion_start_ix = Some(ix); - } - "}" => { - if let Some(start_ix) = expansion_start_ix { - expansion_ranges.push(start_ix..ix + 1); - } - expansion_start_ix = None; - } - _ => {} - } - } - - // Starting with a single pattern, process each brace expansion by cloning - // the pattern once per element of the expansion. - let mut unexpanded_patterns = vec![]; - let mut expanded_patterns = vec![pattern.to_string()]; - - for outer_range in expansion_ranges.into_iter().rev() { - let inner_range = (outer_range.start + 1)..(outer_range.end - 1); - std::mem::swap(&mut unexpanded_patterns, &mut expanded_patterns); - for unexpanded_pattern in unexpanded_patterns.drain(..) { - for part in unexpanded_pattern[inner_range.clone()].split(',') { - let mut expanded_pattern = unexpanded_pattern.clone(); - expanded_pattern.replace_range(outer_range.clone(), part); - expanded_patterns.push(expanded_pattern); - } - } - } - - // Parse the final glob patterns and add them to the set. - for pattern in expanded_patterns { - let pattern = glob::Pattern::new(&pattern)?; - self.patterns.push(pattern); - } - - Ok(()) - } - - pub fn matches(&self, path: &Path) -> bool { - self.patterns - .iter() - .any(|pattern| pattern.matches_path(path)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_glob_set() { - let mut watch = LspGlobSet::default(); - watch.add_pattern("/a/**/*.rs").unwrap(); - watch.add_pattern("/a/**/Cargo.toml").unwrap(); - - assert!(watch.matches("/a/b.rs".as_ref())); - assert!(watch.matches("/a/b/c.rs".as_ref())); - - assert!(!watch.matches("/b/c.rs".as_ref())); - assert!(!watch.matches("/a/b.ts".as_ref())); - } - - #[test] - fn test_brace_expansion() { - let mut watch = LspGlobSet::default(); - watch.add_pattern("/a/*.{ts,js,tsx}").unwrap(); - - assert!(watch.matches("/a/one.js".as_ref())); - assert!(watch.matches("/a/two.ts".as_ref())); - assert!(watch.matches("/a/three.tsx".as_ref())); - - assert!(!watch.matches("/a/one.j".as_ref())); - assert!(!watch.matches("/a/two.s".as_ref())); - assert!(!watch.matches("/a/three.t".as_ref())); - assert!(!watch.matches("/a/four.t".as_ref())); - assert!(!watch.matches("/a/five.xt".as_ref())); - } - - #[test] - fn test_multiple_brace_expansion() { - let mut watch = LspGlobSet::default(); - watch.add_pattern("/a/{one,two,three}.{b*c,d*e}").unwrap(); - - assert!(watch.matches("/a/one.bic".as_ref())); - assert!(watch.matches("/a/two.dole".as_ref())); - assert!(watch.matches("/a/three.deeee".as_ref())); - - assert!(!watch.matches("/a/four.bic".as_ref())); - assert!(!watch.matches("/a/one.be".as_ref())); - } -} diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index 13809622f9e3191cf4b12eaaa0347c3f98e0f050..4b759c4240984da4b35b4f00dde9a48c61cef0c5 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -1,6 +1,5 @@ mod ignore; mod lsp_command; -mod lsp_glob_set; mod project_settings; pub mod search; pub mod terminals; @@ -19,6 +18,7 @@ use futures::{ future::{try_join_all, Shared}, AsyncWriteExt, Future, FutureExt, StreamExt, TryFutureExt, }; +use globset::{Glob, GlobSet, GlobSetBuilder}; use gpui::{ AnyModelHandle, AppContext, AsyncAppContext, BorrowAppContext, Entity, ModelContext, ModelHandle, Task, WeakModelHandle, @@ -41,7 +41,6 @@ use lsp::{ DocumentHighlightKind, LanguageServer, LanguageServerId, }; use lsp_command::*; -use lsp_glob_set::LspGlobSet; use postage::watch; use project_settings::ProjectSettings; use rand::prelude::*; @@ -226,7 +225,7 @@ pub enum LanguageServerState { language: Arc, adapter: Arc, server: Arc, - watched_paths: LspGlobSet, + watched_paths: HashMap, simulate_disk_based_diagnostics_completion: Option>, }, } @@ -2867,10 +2866,39 @@ impl Project { if let Some(LanguageServerState::Running { watched_paths, .. }) = self.language_servers.get_mut(&language_server_id) { - watched_paths.clear(); + eprintln!("change watch"); + let mut builders = HashMap::default(); for watcher in params.watchers { - watched_paths.add_pattern(&watcher.glob_pattern).log_err(); + eprintln!(" {}", watcher.glob_pattern); + for worktree in &self.worktrees { + if let Some(worktree) = worktree.upgrade(cx) { + let worktree = worktree.read(cx); + if let Some(abs_path) = worktree.abs_path().to_str() { + if let Some(suffix) = watcher + .glob_pattern + .strip_prefix(abs_path) + .and_then(|s| s.strip_prefix(std::path::MAIN_SEPARATOR)) + { + if let Some(glob) = Glob::new(suffix).log_err() { + builders + .entry(worktree.id()) + .or_insert_with(|| GlobSetBuilder::new()) + .add(glob); + } + break; + } + } + } + } + } + + watched_paths.clear(); + for (worktree_id, builder) in builders { + if let Ok(globset) = builder.build() { + watched_paths.insert(worktree_id, globset); + } } + cx.notify(); } } @@ -4707,25 +4735,39 @@ impl Project { changes: &HashMap<(Arc, ProjectEntryId), PathChange>, cx: &mut ModelContext, ) { + if changes.is_empty() { + return; + } + let worktree_id = worktree_handle.read(cx).id(); + let mut language_server_ids = self + .language_server_ids + .iter() + .filter_map(|((server_worktree_id, _), server_id)| { + (*server_worktree_id == worktree_id).then_some(*server_id) + }) + .collect::>(); + language_server_ids.sort(); + language_server_ids.dedup(); + let abs_path = worktree_handle.read(cx).abs_path(); - for ((server_worktree_id, _), server_id) in &self.language_server_ids { - if *server_worktree_id == worktree_id { - if let Some(server) = self.language_servers.get(server_id) { - if let LanguageServerState::Running { - server, - watched_paths, - .. - } = server - { + for server_id in &language_server_ids { + if let Some(server) = self.language_servers.get(server_id) { + if let LanguageServerState::Running { + server, + watched_paths, + .. + } = server + { + if let Some(watched_paths) = watched_paths.get(&worktree_id) { let params = lsp::DidChangeWatchedFilesParams { changes: changes .iter() .filter_map(|((path, _), change)| { - let path = abs_path.join(path); - if watched_paths.matches(&path) { + if watched_paths.is_match(&path) { Some(lsp::FileEvent { - uri: lsp::Url::from_file_path(path).unwrap(), + uri: lsp::Url::from_file_path(abs_path.join(path)) + .unwrap(), typ: match change { PathChange::Added => lsp::FileChangeType::CREATED, PathChange::Removed => lsp::FileChangeType::DELETED, diff --git a/crates/project/src/project_tests.rs b/crates/project/src/project_tests.rs index e7b1a84924eb2f5b25b519177ba9bcd5039eb000..69bcea8ce0426f7fe812618542336f3a018262f3 100644 --- a/crates/project/src/project_tests.rs +++ b/crates/project/src/project_tests.rs @@ -1,6 +1,7 @@ use crate::{worktree::WorktreeHandle, Event, *}; use fs::{FakeFs, LineEnding, RealFs}; use futures::{future, StreamExt}; +use globset::Glob; use gpui::{executor::Deterministic, test::subscribe, AppContext}; use language::{ language_settings::{AllLanguageSettings, LanguageSettingsContent}, @@ -505,7 +506,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon register_options: serde_json::to_value( lsp::DidChangeWatchedFilesRegistrationOptions { watchers: vec![lsp::FileSystemWatcher { - glob_pattern: "*.{rs,c}".to_string(), + glob_pattern: "/the-root/*.{rs,c}".to_string(), kind: None, }], }, @@ -3393,7 +3394,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) { search_query, false, true, - vec![glob::Pattern::new("*.odd").unwrap()], + vec![Glob::new("*.odd").unwrap().compile_matcher()], Vec::new() ), cx @@ -3411,7 +3412,7 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) { search_query, false, true, - vec![glob::Pattern::new("*.rs").unwrap()], + vec![Glob::new("*.rs").unwrap().compile_matcher()], Vec::new() ), cx @@ -3433,8 +3434,8 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) { false, true, vec![ - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap(), + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher(), ], Vec::new() ), @@ -3457,9 +3458,9 @@ async fn test_search_with_inclusions(cx: &mut gpui::TestAppContext) { false, true, vec![ - glob::Pattern::new("*.rs").unwrap(), - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap(), + Glob::new("*.rs").unwrap().compile_matcher(), + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher(), ], Vec::new() ), @@ -3504,7 +3505,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) { false, true, Vec::new(), - vec![glob::Pattern::new("*.odd").unwrap()], + vec![Glob::new("*.odd").unwrap().compile_matcher()], ), cx ) @@ -3527,7 +3528,7 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) { false, true, Vec::new(), - vec![glob::Pattern::new("*.rs").unwrap()], + vec![Glob::new("*.rs").unwrap().compile_matcher()], ), cx ) @@ -3549,8 +3550,8 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) { true, Vec::new(), vec![ - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap(), + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher(), ], ), cx @@ -3573,9 +3574,9 @@ async fn test_search_with_exclusions(cx: &mut gpui::TestAppContext) { true, Vec::new(), vec![ - glob::Pattern::new("*.rs").unwrap(), - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap(), + Glob::new("*.rs").unwrap().compile_matcher(), + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher(), ], ), cx @@ -3612,8 +3613,8 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex search_query, false, true, - vec![glob::Pattern::new("*.odd").unwrap()], - vec![glob::Pattern::new("*.odd").unwrap()], + vec![Glob::new("*.odd").unwrap().compile_matcher()], + vec![Glob::new("*.odd").unwrap().compile_matcher()], ), cx ) @@ -3630,8 +3631,8 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex search_query, false, true, - vec![glob::Pattern::new("*.ts").unwrap()], - vec![glob::Pattern::new("*.ts").unwrap()], + vec![Glob::new("*.ts").unwrap().compile_matcher()], + vec![Glob::new("*.ts").unwrap().compile_matcher()], ), cx ) @@ -3649,12 +3650,12 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex false, true, vec![ - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap() + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher() ], vec![ - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap() + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher() ], ), cx @@ -3673,12 +3674,12 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex false, true, vec![ - glob::Pattern::new("*.ts").unwrap(), - glob::Pattern::new("*.odd").unwrap() + Glob::new("*.ts").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher() ], vec![ - glob::Pattern::new("*.rs").unwrap(), - glob::Pattern::new("*.odd").unwrap() + Glob::new("*.rs").unwrap().compile_matcher(), + Glob::new("*.odd").unwrap().compile_matcher() ], ), cx diff --git a/crates/project/src/search.rs b/crates/project/src/search.rs index ed139c97d37032969af5c042e1ed8a27ad7ef7b7..4b4126fef2e1f8f4cb403c809ca62a136cff5afb 100644 --- a/crates/project/src/search.rs +++ b/crates/project/src/search.rs @@ -1,6 +1,7 @@ use aho_corasick::{AhoCorasick, AhoCorasickBuilder}; use anyhow::Result; use client::proto; +use globset::{Glob, GlobMatcher}; use itertools::Itertools; use language::{char_kind, Rope}; use regex::{Regex, RegexBuilder}; @@ -19,8 +20,8 @@ pub enum SearchQuery { query: Arc, whole_word: bool, case_sensitive: bool, - files_to_include: Vec, - files_to_exclude: Vec, + files_to_include: Vec, + files_to_exclude: Vec, }, Regex { regex: Regex, @@ -28,8 +29,8 @@ pub enum SearchQuery { multiline: bool, whole_word: bool, case_sensitive: bool, - files_to_include: Vec, - files_to_exclude: Vec, + files_to_include: Vec, + files_to_exclude: Vec, }, } @@ -38,8 +39,8 @@ impl SearchQuery { query: impl ToString, whole_word: bool, case_sensitive: bool, - files_to_include: Vec, - files_to_exclude: Vec, + files_to_include: Vec, + files_to_exclude: Vec, ) -> Self { let query = query.to_string(); let search = AhoCorasickBuilder::new() @@ -60,8 +61,8 @@ impl SearchQuery { query: impl ToString, whole_word: bool, case_sensitive: bool, - files_to_include: Vec, - files_to_exclude: Vec, + files_to_include: Vec, + files_to_exclude: Vec, ) -> Result { let mut query = query.to_string(); let initial_query = Arc::from(query.as_str()); @@ -95,40 +96,16 @@ impl SearchQuery { message.query, message.whole_word, message.case_sensitive, - message - .files_to_include - .split(',') - .map(str::trim) - .filter(|glob_str| !glob_str.is_empty()) - .map(|glob_str| glob::Pattern::new(glob_str)) - .collect::>()?, - message - .files_to_exclude - .split(',') - .map(str::trim) - .filter(|glob_str| !glob_str.is_empty()) - .map(|glob_str| glob::Pattern::new(glob_str)) - .collect::>()?, + deserialize_globs(&message.files_to_include)?, + deserialize_globs(&message.files_to_exclude)?, ) } else { Ok(Self::text( message.query, message.whole_word, message.case_sensitive, - message - .files_to_include - .split(',') - .map(str::trim) - .filter(|glob_str| !glob_str.is_empty()) - .map(|glob_str| glob::Pattern::new(glob_str)) - .collect::>()?, - message - .files_to_exclude - .split(',') - .map(str::trim) - .filter(|glob_str| !glob_str.is_empty()) - .map(|glob_str| glob::Pattern::new(glob_str)) - .collect::>()?, + deserialize_globs(&message.files_to_include)?, + deserialize_globs(&message.files_to_exclude)?, )) } } @@ -143,12 +120,12 @@ impl SearchQuery { files_to_include: self .files_to_include() .iter() - .map(ToString::to_string) + .map(|g| g.glob().to_string()) .join(","), files_to_exclude: self .files_to_exclude() .iter() - .map(ToString::to_string) + .map(|g| g.glob().to_string()) .join(","), } } @@ -289,7 +266,7 @@ impl SearchQuery { matches!(self, Self::Regex { .. }) } - pub fn files_to_include(&self) -> &[glob::Pattern] { + pub fn files_to_include(&self) -> &[GlobMatcher] { match self { Self::Text { files_to_include, .. @@ -300,7 +277,7 @@ impl SearchQuery { } } - pub fn files_to_exclude(&self) -> &[glob::Pattern] { + pub fn files_to_exclude(&self) -> &[GlobMatcher] { match self { Self::Text { files_to_exclude, .. @@ -317,14 +294,23 @@ impl SearchQuery { !self .files_to_exclude() .iter() - .any(|exclude_glob| exclude_glob.matches_path(file_path)) + .any(|exclude_glob| exclude_glob.is_match(file_path)) && (self.files_to_include().is_empty() || self .files_to_include() .iter() - .any(|include_glob| include_glob.matches_path(file_path))) + .any(|include_glob| include_glob.is_match(file_path))) } None => self.files_to_include().is_empty(), } } } + +fn deserialize_globs(glob_set: &str) -> Result> { + glob_set + .split(',') + .map(str::trim) + .filter(|glob_str| !glob_str.is_empty()) + .map(|glob_str| Ok(Glob::new(glob_str)?.compile_matcher())) + .collect() +} diff --git a/crates/search/Cargo.toml b/crates/search/Cargo.toml index 14e658e8f843bd71a915e774f9e6fc745c0b1e31..7ef388f7c087638c1ee3f5c2002ab3d2c3371dc7 100644 --- a/crates/search/Cargo.toml +++ b/crates/search/Cargo.toml @@ -27,7 +27,7 @@ serde.workspace = true serde_derive.workspace = true smallvec.workspace = true smol.workspace = true -glob.workspace = true +globset.workspace = true [dev-dependencies] client = { path = "../client", features = ["test-support"] } diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 17f86c153c9b51edba847f4fafb99a8efda9cbbb..d96d77eb005aa099642f01f6499db60363caaf6d 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -2,12 +2,14 @@ use crate::{ SearchOption, SelectNextMatch, SelectPrevMatch, ToggleCaseSensitive, ToggleRegex, ToggleWholeWord, }; +use anyhow::Result; use collections::HashMap; use editor::{ items::active_match_index, scroll::autoscroll::Autoscroll, Anchor, Editor, MultiBuffer, SelectAll, MAX_TAB_TITLE_LEN, }; use futures::StreamExt; +use globset::{Glob, GlobMatcher}; use gpui::{ actions, elements::*, @@ -571,46 +573,30 @@ impl ProjectSearchView { fn build_search_query(&mut self, cx: &mut ViewContext) -> Option { let text = self.query_editor.read(cx).text(cx); - let included_files = match self - .included_files_editor - .read(cx) - .text(cx) - .split(',') - .map(str::trim) - .filter(|glob_str| !glob_str.is_empty()) - .map(|glob_str| glob::Pattern::new(glob_str)) - .collect::>() - { - Ok(included_files) => { - self.panels_with_errors.remove(&InputPanel::Include); - included_files - } - Err(_e) => { - self.panels_with_errors.insert(InputPanel::Include); - cx.notify(); - return None; - } - }; - let excluded_files = match self - .excluded_files_editor - .read(cx) - .text(cx) - .split(',') - .map(str::trim) - .filter(|glob_str| !glob_str.is_empty()) - .map(|glob_str| glob::Pattern::new(glob_str)) - .collect::>() - { - Ok(excluded_files) => { - self.panels_with_errors.remove(&InputPanel::Exclude); - excluded_files - } - Err(_e) => { - self.panels_with_errors.insert(InputPanel::Exclude); - cx.notify(); - return None; - } - }; + let included_files = + match Self::load_glob_set(&self.included_files_editor.read(cx).text(cx)) { + Ok(included_files) => { + self.panels_with_errors.remove(&InputPanel::Include); + included_files + } + Err(_e) => { + self.panels_with_errors.insert(InputPanel::Include); + cx.notify(); + return None; + } + }; + let excluded_files = + match Self::load_glob_set(&self.excluded_files_editor.read(cx).text(cx)) { + Ok(excluded_files) => { + self.panels_with_errors.remove(&InputPanel::Exclude); + excluded_files + } + Err(_e) => { + self.panels_with_errors.insert(InputPanel::Exclude); + cx.notify(); + return None; + } + }; if self.regex { match SearchQuery::regex( text, @@ -640,6 +626,14 @@ impl ProjectSearchView { } } + fn load_glob_set(text: &str) -> Result> { + text.split(',') + .map(str::trim) + .filter(|glob_str| !glob_str.is_empty()) + .map(|glob_str| anyhow::Ok(Glob::new(glob_str)?.compile_matcher())) + .collect() + } + fn select_match(&mut self, direction: Direction, cx: &mut ViewContext) { if let Some(index) = self.active_match_index { let match_ranges = self.model.read(cx).match_ranges.clone(); diff --git a/crates/settings/Cargo.toml b/crates/settings/Cargo.toml index 2cb6637eadc876f375313f502d97ff89aaa3ee4f..1ec0ff4a635551e5877f302375e41d0b8ed0fb62 100644 --- a/crates/settings/Cargo.toml +++ b/crates/settings/Cargo.toml @@ -22,7 +22,6 @@ util = { path = "../util" } anyhow.workspace = true futures.workspace = true -glob.workspace = true json_comments = "0.2" lazy_static.workspace = true postage.workspace = true