internal static ImmutableArray <Words> GetBaseNames(ITypeSymbol type, bool pluralize) { var baseName = TryRemoveInterfacePrefix(type); var parts = StringBreaker.GetWordParts(baseName); var result = GetInterleavedPatterns(parts, baseName, pluralize); parts.Free(); return(result); }
public static IdentifierNameParts CreateIdentifierNameParts(ISymbol symbol, ImmutableArray <NamingRule> rules) { var baseName = RemovePrefixesAndSuffixes(symbol, rules, symbol.Name); var parts = StringBreaker.GetWordParts(baseName); var words = CreateWords(parts, baseName); return(new IdentifierNameParts(baseName, words)); }
internal static ImmutableArray <Words> GetBaseNames(IAliasSymbol alias) { var name = alias.Name; if (alias.Target.IsType && (((INamedTypeSymbol)alias.Target).IsInterfaceType() && CanRemoveInterfacePrefix(name))) { name = name.Substring(1); } var breaks = StringBreaker.GetWordParts(name); var result = GetInterleavedPatterns(breaks, name, pluralize: false); breaks.Free(); return(result); }
private PatternMatch?NonFuzzyMatchPatternChunk( string candidate, TextChunk patternChunk, bool punctuationStripped) { var candidateLength = candidate.Length; var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase); if (caseInsensitiveIndex == 0) { // We found the pattern at the start of the candidate. This is either an exact or // prefix match. if (patternChunk.Text.Length == candidateLength) { // Lengths were the same, this is either a case insensitive or sensitive exact match. return(new PatternMatch( PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text, matchedSpan: GetMatchedSpan(0, candidateLength))); } else { // 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))); } } ArrayBuilder <TextSpan> candidateHumpsOpt = null; try { var patternIsLowercase = patternChunk.IsLowercase; if (caseInsensitiveIndex > 0) { // We found the pattern somewhere in the candidate. This could be a substring match. // However, we don't want to be overaggressive in returning just any substring results. // So do a few more checks to make sure this is a good result. if (!patternIsLowercase) { // Pattern contained uppercase letters. This is a strong indication from the // user that they expect the same letters to be uppercase in the result. As // such, only return this if we can find this pattern exactly in the candidate. var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None); if (caseSensitiveIndex > 0) { return(new PatternMatch( PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length))); } } else { // Pattern was all lowercase. This can lead to lots of false positives. For // example, we don't want "bin" to match "CombineUnits". Instead, we want it // to match "BinaryOperator". As such, make sure our match looks like it's // starting an actual word in the candidate. // Do a quick check to avoid the expensive work of having to go get the candidate // humps. if (char.IsUpper(candidate[caseInsensitiveIndex])) { return(new PatternMatch(PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: false, matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length))); } candidateHumpsOpt = StringBreaker.GetWordParts(candidate); for (int i = 0, n = candidateHumpsOpt.Count; i < n; i++) { var hump = TextSpan.FromBounds(candidateHumpsOpt[i].Start, candidateLength); if (PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.IgnoreCase)) { return(new PatternMatch(PatternMatchKind.Substring, punctuationStripped, isCaseSensitive: PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.None), matchedSpan: GetMatchedSpan(hump.Start, patternChunk.Text.Length))); } } } } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. if (candidateHumpsOpt == null) { candidateHumpsOpt = StringBreaker.GetWordParts(candidate); } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. return(TryCamelCaseMatch( candidate, patternChunk, punctuationStripped, patternIsLowercase, candidateHumpsOpt)); } finally { candidateHumpsOpt?.Free(); } }
private static ImmutableArray <string> BreakIntoWordParts(string identifier) => PartListToSubstrings(identifier, StringBreaker.GetWordParts(identifier));
private PatternMatch?NonFuzzyMatchPatternChunk( string candidate, TextChunk patternChunk, bool punctuationStripped) { var candidateLength = candidate.Length; var caseInsensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.IgnoreCase); if (caseInsensitiveIndex == 0) { // We found the pattern at the start of the candidate. This is either an exact or // prefix match. if (patternChunk.Text.Length == candidateLength) { // Lengths were the same, this is either a case insensitive or sensitive exact match. return(new PatternMatch( PatternMatchKind.Exact, punctuationStripped, isCaseSensitive: candidate == patternChunk.Text, matchedSpan: GetMatchedSpan(0, candidateLength))); } else { // 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))); } } ArrayBuilder <TextSpan> candidateHumpsOpt = null; try { var patternIsLowercase = patternChunk.IsLowercase; if (caseInsensitiveIndex > 0) { // We found the pattern somewhere in the candidate. This could be a substring match. // However, we don't want to be overaggressive in returning just any substring results. // So do a few more checks to make sure this is a good result. if (!patternIsLowercase) { // Pattern contained uppercase letters. This is a strong indication from the // user that they expect the same letters to be uppercase in the result. As // such, only return this if we can find this pattern exactly in the candidate. var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None); if (caseSensitiveIndex > 0) { if (char.IsUpper(candidate[caseInsensitiveIndex])) { return(new PatternMatch( PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length))); } else { return(new PatternMatch( PatternMatchKind.NonLowercaseSubstring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length))); } } } else { // Pattern was all lowercase. This can lead to lots of hits. For example, "bin" in // "CombineUnits". Instead, we want it to match "Operator[|Bin|]ary" first rather than // Com[|bin|]eUnits // If the lowercase search string matched what looks to be the start of a word then that's a // reasonable hit. This is equivalent to 'bin' matching 'Operator[|Bin|]ary' if (char.IsUpper(candidate[caseInsensitiveIndex])) { return(new PatternMatch(PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: false, matchedSpan: GetMatchedSpan(caseInsensitiveIndex, patternChunk.Text.Length))); } // 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' candidateHumpsOpt = StringBreaker.GetWordParts(candidate); for (int i = 0, n = candidateHumpsOpt.Count; i < n; i++) { var hump = TextSpan.FromBounds(candidateHumpsOpt[i].Start, candidateLength); if (PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.IgnoreCase)) { return(new PatternMatch(PatternMatchKind.StartOfWordSubstring, punctuationStripped, isCaseSensitive: PartStartsWith(candidate, hump, patternChunk.Text, CompareOptions.None), matchedSpan: GetMatchedSpan(hump.Start, patternChunk.Text.Length))); } } } } // Didn't have an exact/prefix match, or a high enough quality substring match. // See if we can find a camel case match. if (candidateHumpsOpt == null) { candidateHumpsOpt = StringBreaker.GetWordParts(candidate); } // 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, candidateHumpsOpt); 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 // user types 'bin' we want to match 'OperatorBinary' (start of word) or 'BinaryInformationNode' (camel // humps) before matching 'Combine'. // // We only do this for strings longer than three characters to avoid too many false positives when the // user has only barely started writing a word. if (patternIsLowercase && caseInsensitiveIndex > 0 && patternChunk.Text.Length >= 3) { var caseSensitiveIndex = _compareInfo.IndexOf(candidate, patternChunk.Text, CompareOptions.None); if (caseSensitiveIndex > 0) { return(new PatternMatch( PatternMatchKind.LowercaseSubstring, punctuationStripped, isCaseSensitive: true, matchedSpan: GetMatchedSpan(caseSensitiveIndex, patternChunk.Text.Length))); } } return(null); } finally { candidateHumpsOpt?.Free(); } }