What's wrong
ResolveGlob (TextFilter/TextFilter.cs, around lines 406–416) compiles every token with Glob.Parse from DotNet.Glob. DotNet.Glob is a file-path glob library, so * and ? stop at path separators (/ and \). TextFilter filters arbitrary text, and GetHint and the README describe * and ? as plain wildcards with no path semantics. As soon as the text contains a slash or backslash, a wildcard can no longer reach across it.
Failure scenario (reproduced)
A filter box over a list of file paths: the user types *readme* and docs/readme.md disappears, while readme.md stays. The same thing happens with:
| Text |
Pattern |
Match option |
Result |
AC/DC |
AC* |
ByWordAny |
no match |
1/2 |
1?2 |
ByWordAny |
no match |
src/Foo.cs |
*.cs |
ByWholeString |
no match (Foo.cs matches) |
C:\temp\a.txt |
*.txt |
ByWholeString |
no match |
It affects every match option and both case settings. Paths, URLs, dates (1/2/2026), fractions and band names are all ordinary things to filter.
Repro (MSTest, all fail today):
[TestMethod] public void StarMatchesAcrossSlash() => Assert.IsTrue(TextFilter.IsMatch("AC/DC", "AC*", TextFilterType.Glob, TextFilterMatchOptions.ByWordAny));
[TestMethod] public void QuestionMarkMatchesSlash() => Assert.IsTrue(TextFilter.IsMatch("1/2", "1?2", TextFilterType.Glob, TextFilterMatchOptions.ByWordAny));
[TestMethod] public void StarMatchesPath() => Assert.IsTrue(TextFilter.IsMatch("src/Foo.cs", "*.cs", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
[TestMethod] public void StarMatchesBackslashPath() => Assert.IsTrue(TextFilter.IsMatch(@"C:\temp\a.txt", "*.txt", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
[TestMethod] public void FilterKeepsPathItems() { var r = TextFilter.Filter(new[] { "docs/readme.md", "readme.md" }, "*readme*").ToList(); Assert.AreEqual(2, r.Count); }
Suggested fix
Either of these:
- Translate glob tokens to regex yourself (preferred):
* → .*, ? → ., keep [...] ranges (handling a half-typed range the way the current code does), and Regex.Escape everything else, anchored with ^…$. This can reuse the existing regex cache, timeout, and CultureInvariant | IgnoreCase handling, and it drops a dependency whose semantics don't fit.
- Or keep DotNet.Glob and map
/ and \ to a private-use character (e.g. U+E000) in both the text and the pattern before matching.
Acceptance: the five tests above pass, and the existing glob tests still pass.
What's wrong
ResolveGlob(TextFilter/TextFilter.cs, around lines 406–416) compiles every token withGlob.Parsefrom DotNet.Glob. DotNet.Glob is a file-path glob library, so*and?stop at path separators (/and\). TextFilter filters arbitrary text, andGetHintand the README describe*and?as plain wildcards with no path semantics. As soon as the text contains a slash or backslash, a wildcard can no longer reach across it.Failure scenario (reproduced)
A filter box over a list of file paths: the user types
*readme*anddocs/readme.mddisappears, whilereadme.mdstays. The same thing happens with:AC/DCAC*1/21?2src/Foo.cs*.csFoo.csmatches)C:\temp\a.txt*.txtIt affects every match option and both case settings. Paths, URLs, dates (
1/2/2026), fractions and band names are all ordinary things to filter.Repro (MSTest, all fail today):
Suggested fix
Either of these:
*→.*,?→., keep[...]ranges (handling a half-typed range the way the current code does), andRegex.Escapeeverything else, anchored with^…$. This can reuse the existing regex cache, timeout, andCultureInvariant | IgnoreCasehandling, and it drops a dependency whose semantics don't fit./and\to a private-use character (e.g. U+E000) in both the text and the pattern before matching.Acceptance: the five tests above pass, and the existing glob tests still pass.