Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions TextFilter.Test/TextFilterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,39 @@ static int ScoreOf(string s)
Assert.IsNotEmpty(result);
}

[TestMethod]
[DataRow("foo bar", "foo bar")]
[DataRow("my file.txt", "my file.txt")]
[DataRow("my file.txt", " my file.txt ")]
[DataRow("my file.txt", "my *.txt")]
public void GlobByWholeStringMatchesTextContainingASpace(string text, string filter)
{
Assert.IsTrue(TextFilter.IsMatch(text, filter, TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
}

[TestMethod]
public void GlobByWholeStringWithASpaceStillNeedsTheWholeTextToMatch()
{
Assert.IsFalse(TextFilter.IsMatch("foo bar baz", "foo bar", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsFalse(TextFilter.IsMatch("foo bar", "foo bar", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsFalse(TextFilter.IsMatch("Foo bar", "foo bar", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsTrue(TextFilter.IsMatch("Foo Bar", "foo bar", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString, TextFilterCaseSensitivity.CaseInsensitive));
}

[TestMethod]
public void GlobByWholeStringKeepsMultiplePatternsAndPrefixedTokens()
{
// #113: each pattern is still tried on its own.
Assert.IsTrue(TextFilter.IsMatch("a.png", "*.jpg *.png", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsFalse(TextFilter.IsMatch("a.gif", "*.jpg *.png", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));

// A filter with an excluded or required token is not tried whole, so those tokens behave as before.
Assert.IsFalse(TextFilter.IsMatch("a.png", "*.png -a.*", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsTrue(TextFilter.IsMatch("b.png", "*.png -a.*", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsTrue(TextFilter.IsMatch("a.png", "*.png +a.*", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
Assert.IsFalse(TextFilter.IsMatch("b.png", "*.png +a.*", TextFilterType.Glob, TextFilterMatchOptions.ByWholeString));
}

// Assemblies compiled against 1.6 or earlier bind to these exact signatures, so each must still
// exist in the binary even though source callers now resolve to the case-sensitivity overloads.
[TestMethod]
Expand Down
14 changes: 14 additions & 0 deletions TextFilter/TextFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,20 @@ public static bool DoesMatchGlob(string text, string filter, TextFilterMatchOpti
return true; // empty filter matches all text
}

// The filter is split on whitespace, so under ByWholeString no single token can equal a text that
// contains a space ("my file.txt"). With only plain tokens, try the whole filter as one glob first;
// the per-token pass below still runs, so "*.jpg *.png" keeps matching "a.png" (#113).
string wholeFilter = filter.Trim();
if (textFilterMatchOptions is TextFilterMatchOptions.ByWholeString
&& filterTokens.Count == 1
&& filterTokens.ContainsKey(TextFilterTokenType.Optional)
&& wholeFilter.Any(char.IsWhiteSpace)
&& ResolveGlob(wholeFilter, caseSensitivity) is Glob[] wholeFilterGlobs
&& IsGlobMatch(wholeFilterGlobs, text))
{
return true;
}

if (!filterTokens.TryGetValue(TextFilterTokenType.Excluded, out HashSet<string>? excludedTokens))
{
excludedTokens = [];
Expand Down
Loading