-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve pattern matching when user is likely providing camel humps #75757
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -114,9 +114,19 @@ private static bool ContainsUpperCaseLetter(string pattern) | |
for (var i = 0; i < pattern.Length; i++) | ||
{ | ||
if (char.IsUpper(pattern[i])) | ||
{ | ||
return true; | ||
} | ||
} | ||
|
||
return false; | ||
} | ||
|
||
private static bool ContainsLowerCaseLetter(string pattern) | ||
{ | ||
// Expansion of "foreach(char ch in pattern)" to avoid a CharEnumerator allocation | ||
for (var i = 0; i < pattern.Length; i++) | ||
{ | ||
if (char.IsLower(pattern[i])) | ||
return true; | ||
} | ||
|
||
return false; | ||
|
@@ -153,6 +163,8 @@ private static bool ContainsUpperCaseLetter(string pattern) | |
in TextChunk patternChunk, | ||
bool punctuationStripped) | ||
{ | ||
using var candidateHumps = TemporaryArray<TextSpan>.Empty; | ||
|
||
var candidateLength = candidate.Length; | ||
|
||
var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase); | ||
|
@@ -170,15 +182,31 @@ private static bool ContainsUpperCaseLetter(string pattern) | |
} | ||
else | ||
{ | ||
var isCaseSensitive = _compareInfo.IsPrefix(candidate, patternChunk.Text); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no. This is stating if it's case sensitive or not. if it's a prefix that it is, otherwise it isn't and it must have been case inseisitive. |
||
|
||
if (!isCaseSensitive && patternChunk.IsUppercase) | ||
{ | ||
// The user wrote something all upper case, but happened to match the prefix of the word. For | ||
// example, matching `CR` against both `Create` (a case insensitive prefix match) and `CreateRange` | ||
// (a camel hump match). We want to prefer the latter in this case as the all upper case string | ||
// is a strong signal they wanted camel hump matching here. | ||
PopulateCandidateHumps(); | ||
|
||
// Note: ensure that we match here case sensitively as well. We only want to take this if their | ||
// camel humps actually matched real word starts. | ||
var match = TryCamelCaseMatch(candidate, patternChunk, punctuationStripped, isLowercase: false, candidateHumps); | ||
if (match is { IsCaseSensitive: true }) | ||
return match; | ||
|
||
// Deliberately fall through. | ||
} | ||
|
||
// Lengths were the same, this is either a case insensitive or sensitive prefix match. | ||
return new PatternMatch( | ||
PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive: _compareInfo.IsPrefix(candidate, patternChunk.Text), | ||
matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length)); | ||
PatternMatchKind.Prefix, punctuationStripped, isCaseSensitive, matchedSpan: GetMatchedSpan(0, patternChunk.Text.Length)); | ||
} | ||
} | ||
|
||
using var candidateHumps = TemporaryArray<TextSpan>.Empty; | ||
|
||
var patternIsLowercase = patternChunk.IsLowercase; | ||
if (caseInsensitiveIndex > 0) | ||
{ | ||
|
@@ -221,7 +249,8 @@ private static bool ContainsUpperCaseLetter(string pattern) | |
// Now do the more expensive check to see if we're at the start of a word. This is to catch | ||
// word matches like CombineBinary. We want to find the hit against '[|Bin|]ary' not | ||
// 'Com[|bin|]e' | ||
StringBreaker.AddWordParts(candidate, ref candidateHumps.AsRef()); | ||
PopulateCandidateHumps(); | ||
|
||
for (int i = 0, n = candidateHumps.Count; i < n; i++) | ||
{ | ||
var hump = TextSpan.FromBounds(candidateHumps[i].Start, candidateLength); | ||
|
@@ -235,16 +264,17 @@ private static bool ContainsUpperCaseLetter(string pattern) | |
} | ||
} | ||
|
||
// Didn't have an exact/prefix match, or a high enough quality substring match. | ||
// See if we can find a camel case match. | ||
if (candidateHumps.Count == 0) | ||
StringBreaker.AddWordParts(candidate, ref candidateHumps.AsRef()); | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this code block looks a bit confusing There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not sure what to do about that :) |
||
// Didn't have an exact/prefix match, or a high enough quality substring match. | ||
// See if we can find a camel case match. | ||
PopulateCandidateHumps(); | ||
|
||
// Didn't have an exact/prefix match, or a high enough quality substring match. | ||
// See if we can find a camel case match. | ||
var match = TryCamelCaseMatch(candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumps); | ||
if (match != null) | ||
return match; | ||
// Didn't have an exact/prefix match, or a high enough quality substring match. | ||
// See if we can find a camel case match. | ||
var match = TryCamelCaseMatch(candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumps); | ||
if (match != null) | ||
return match; | ||
} | ||
|
||
// If pattern was all lowercase, we allow it to match an all lowercase section of the candidate. But | ||
// only after we've tried all other forms first. This is the weakest of all matches. For example, if | ||
|
@@ -265,6 +295,12 @@ private static bool ContainsUpperCaseLetter(string pattern) | |
} | ||
|
||
return null; | ||
|
||
void PopulateCandidateHumps() | ||
{ | ||
if (candidateHumps.Count == 0) | ||
StringBreaker.AddWordParts(candidate, ref candidateHumps.AsRef()); | ||
} | ||
} | ||
|
||
private TextSpan? GetMatchedSpan(int start, int length) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as before. just clearer imo.