private SearchPreProcessResult <T> PreProcessFileSystemNameSearch <T>(SearchParams searchParams, Func <IPathMatcher, T, IPathComparer, bool> matchName, Func <IPathMatcher, T, IPathComparer, bool> matchRelativeName) where T : FileSystemName { // Regex has its own set of rules for pre-processing if (searchParams.Regex) { return(PreProcessFileSystemNameRegularExpressionSearch( searchParams, matchName, matchRelativeName)); } // Check pattern is not empty var pattern = (searchParams.SearchString ?? "").Trim(); if (string.IsNullOrWhiteSpace(pattern)) { return(null); } // Split pattern around ";", normalize directory separators and // add "*" if not a whole word search var patterns = pattern .Split(new[] { ';' }) .Where(x => !string.IsNullOrWhiteSpace(x.Trim())) .Select(x => x.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)) .Select(x => { // Exception to ".gitignore" syntax: If the search string doesn't contain any special // character, surround the pattern with "*" so that we match sub-strings. // TODO(rpaquay): What about "."? Special or not? if (x.IndexOf(Path.DirectorySeparatorChar) < 0 && x.IndexOf('*') < 0) { if (!searchParams.MatchWholeWord) { x = "*" + x + "*"; } } return(x); }) .ToReadOnlyCollection(); var matcher = new AnyPathMatcher(patterns.Select(PatternParser.ParsePattern)); var comparer = searchParams.MatchCase ? PathComparerRegistry.CaseSensitive : PathComparerRegistry.CaseInsensitive; if (patterns.Any(x => x.Contains(Path.DirectorySeparatorChar))) { return(new SearchPreProcessResult <T> { Matcher = (item) => matchRelativeName(matcher, item, comparer) }); } else { return(new SearchPreProcessResult <T> { Matcher = (item) => matchName(matcher, item, comparer) }); } }
private static void AssertMatch(MatchKind kind, object[,] expectedResults, bool optimize) { Debug.WriteLine(string.Format("====================================================================")); Debug.WriteLine(string.Format("Verifying expected result for {0} entries with optimization={1}.", expectedResults.GetLength(0), optimize)); Debug.WriteLine(string.Format("====================================================================")); for (var i = 0; i < expectedResults.GetLength(0); i++) { var pattern = (string)expectedResults[i, 0]; var path = (string)expectedResults[i, 1]; var result = (bool)expectedResults[i, 2]; Debug.WriteLine(string.Format("Matching \"{0}\" pattern \"{1}\" against path \"{2}\" should return {3}.", kind, pattern, path, result)); pattern = pattern.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); IPathMatcher matcher; if (optimize) { matcher = new AnyPathMatcher(Enumerable.Repeat(PatternParser.ParsePattern(pattern), 1)); } else { matcher = PatternParser.ParsePattern(pattern); } if (kind == MatchKind.Directory) { Assert.AreEqual(result, matcher.MatchDirectoryName(new RelativePath(path), SystemPathComparer.Instance)); } else { Assert.AreEqual(result, matcher.MatchFileName(new RelativePath(path), SystemPathComparer.Instance)); } } }
private SearchPreProcessResult <T> PreProcessFileSystemNameSearch <T>(SearchParams searchParams, Func <IPathMatcher, T, IPathComparer, bool> matchName, Func <IPathMatcher, T, IPathComparer, bool> matchRelativeName) { // Regex has its own set of rules for pre-processing if (searchParams.Regex) { return(PreProcessFileSystemNameRegularExpressionSearch( searchParams, matchName, matchRelativeName)); } // Check pattern is not empty var pattern = (searchParams.SearchString ?? "").Trim(); if (string.IsNullOrWhiteSpace(pattern)) { return(null); } // Split pattern around ";", normalize directory separators and // add "*" if not a whole word search var patterns = pattern .Split(new[] { ';' }) .Where(x => !string.IsNullOrWhiteSpace(x.Trim())) .Select(x => x.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar)) .ToList(); // Split patterns into "include" and "exclude" patterns. // "exclude" patterns are defined as any pattern starting with "-". var includePatterns = patterns .Where(x => !x.StartsWith("-")) .ToList(); var excludePatterns = patterns .Where(x => x.StartsWith("-")) .Select(x => x.Substring(1)) .Where(x => !string.IsNullOrWhiteSpace(x)) .ToList(); // Process qouble quotes, and add implicit wildcards if needed includePatterns = MapQuotesAndImplicitWildcards(searchParams, includePatterns).ToList(); excludePatterns = MapQuotesAndImplicitWildcards(searchParams, excludePatterns).ToList(); // If no include pattern, assume implicit "*" if (includePatterns.Count == 0) { includePatterns.Add("*"); } var includeMatcher = new AnyPathMatcher(includePatterns.Select(PatternParser.ParsePattern)); // Perf: Use "null" matcher if exclude pattern list is empty var excludeMatcher = (excludePatterns.Count == 0 ? null : new AnyPathMatcher(excludePatterns.Select(PatternParser.ParsePattern))); var comparer = searchParams.MatchCase ? PathComparerRegistry.CaseSensitive : PathComparerRegistry.CaseInsensitive; if (patterns.Any(x => x.Contains(Path.DirectorySeparatorChar))) { return(new SearchPreProcessResult <T> { Matcher = (item) => { if (excludeMatcher != null && matchRelativeName(excludeMatcher, item, comparer)) { return false; } return matchRelativeName(includeMatcher, item, comparer); } }); } else { return(new SearchPreProcessResult <T> { Matcher = (item) => { if (excludeMatcher != null && matchName(excludeMatcher, item, comparer)) { return false; } return matchName(includeMatcher, item, comparer); } }); } }