Skip to content

Glob * and ? never match across / or \, so any item containing a slash is filtered out #114

Description

@matt-edmondson

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.

Activity

matt-edmondson commented on Sep 26, 2026

@matt-edmondson
ContributorAuthor

Triage


Generated by Claude Code

added a commit that references this issue on Sep 27, 2026
df1c960
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions