diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -10,7 +10,7 @@ #[cfg(feature = "with-re2")] use crate::re2::Re2; use crate::{ - filepatterns::PatternResult, + filepatterns::{build_single_regex, PatternResult}, utils::hg_path::{HgPath, HgPathBuf}, DirsMultiset, DirstateMapError, IgnorePattern, PatternError, PatternSyntax, @@ -244,6 +244,57 @@ Err(PatternError::Re2NotInstalled) } +/// Returns a function that matches an `HgPath` against the regex formed by +/// the given patterns. +fn build_regex_match<'a>( + ignore_patterns: &'a [&'a IgnorePattern], +) -> PatternResult<(Vec, Box bool + Sync>)> { + let mut all_groups = vec![]; + let regexps: Result, PatternError> = ignore_patterns + .into_iter() + .map(|k| build_single_regex(*k)) + .collect(); + let regexps = regexps?; + let full_regex = regexps.join(&b'|'); + + let mut start_index = 0; + let mut group_size = 0; + + for (index, re) in regexps.iter().enumerate() { + let piece_size = re.len(); + if piece_size > MAX_RE_SIZE { + return Err(PatternError::TooLong(piece_size)); + } + if (group_size + piece_size) > MAX_RE_SIZE { + let group = ®exps[start_index..index]; + all_groups.push(group.join(&b'|')); + start_index = index; + group_size = 0 + } + group_size += piece_size + 1; + } + + let func = if start_index == 0 { + let matcher = re_matcher(&full_regex)?; + Box::new(move |filename: &HgPath| matcher(filename)) + as Box bool + Sync> + } else { + let group = ®exps[start_index..]; + all_groups.push(group.join(&b'|')); + + let all_matchers: PatternResult> = + all_groups.iter().map(|group| re_matcher(group)).collect(); + let all_matchers = all_matchers?; + + let ret = Box::new(move |filename: &HgPath| { + all_matchers.iter().any(|f| f(filename)) + }); + ret as Box bool + Sync> + }; + + Ok((full_regex, func)) +} + /// Returns roots and directories corresponding to each pattern. /// /// This calculates the roots and directories exactly matching the patterns and