Skip to content

Commit 955542d

Browse files
author
Andy
authored
Simplify matchTextChunk (#23081)
1 parent fd553df commit 955542d

File tree

1 file changed

+42
-53
lines changed

1 file changed

+42
-53
lines changed

src/services/patternMatcher.ts

Lines changed: 42 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ namespace ts {
173173
return spans;
174174
}
175175

176-
function matchTextChunk(candidate: string, chunk: TextChunk, stringToWordSpans: Map<TextSpan[]>): PatternMatch {
176+
function matchTextChunk(candidate: string, chunk: TextChunk, stringToWordSpans: Map<TextSpan[]>): PatternMatch | undefined {
177177
const index = indexOfIgnoringCase(candidate, chunk.textLowerCase);
178178
if (index === 0) {
179179
if (chunk.text.length === candidate.length) {
@@ -188,61 +188,48 @@ namespace ts {
188188
}
189189
}
190190

191-
const isLowercase = chunk.isLowerCase;
192-
if (isLowercase) {
193-
if (index > 0) {
194-
// c) If the part is entirely lowercase, then check if it is contained anywhere in the
195-
// candidate in a case insensitive manner. If so, return that there was a substring
196-
// match.
197-
//
198-
// Note: We only have a substring match if the lowercase part is prefix match of some
199-
// word part. That way we don't match something like 'Class' when the user types 'a'.
200-
// But we would match 'FooAttribute' (since 'Attribute' starts with 'a').
201-
const wordSpans = getWordSpans(candidate, stringToWordSpans);
202-
for (const span of wordSpans) {
203-
if (partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ true)) {
204-
return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false));
205-
}
191+
if (chunk.isLowerCase) {
192+
if (index === -1) return undefined;
193+
// c) If the part is entirely lowercase, then check if it is contained anywhere in the
194+
// candidate in a case insensitive manner. If so, return that there was a substring
195+
// match.
196+
//
197+
// Note: We only have a substring match if the lowercase part is prefix match of some
198+
// word part. That way we don't match something like 'Class' when the user types 'a'.
199+
// But we would match 'FooAttribute' (since 'Attribute' starts with 'a').
200+
const wordSpans = getWordSpans(candidate, stringToWordSpans);
201+
for (const span of wordSpans) {
202+
if (partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ true)) {
203+
return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false));
206204
}
207205
}
206+
// d) Is the pattern a substring of the candidate starting on one of the candidate's word boundaries?
207+
// We could check every character boundary start of the candidate for the pattern. However, that's
208+
// an m * n operation in the wost case. Instead, find the first instance of the pattern
209+
// substring, and see if it starts on a capital letter. It seems unlikely that the user will try to
210+
// filter the list based on a substring that starts on a capital letter and also with a lowercase one.
211+
// (Pattern: fogbar, Candidate: quuxfogbarFogBar).
212+
if (chunk.text.length < candidate.length && isUpperCaseLetter(candidate.charCodeAt(index))) {
213+
return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ false);
214+
}
208215
}
209216
else {
210-
// d) If the part was not entirely lowercase, then check if it is contained in the
217+
// e) If the part was not entirely lowercase, then check if it is contained in the
211218
// candidate in a case *sensitive* manner. If so, return that there was a substring
212219
// match.
213220
if (candidate.indexOf(chunk.text) > 0) {
214221
return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ true);
215222
}
216-
}
217-
218-
if (!isLowercase) {
219-
// e) If the part was not entirely lowercase, then attempt a camel cased match as well.
223+
// f) If the part was not entirely lowercase, then attempt a camel cased match as well.
220224
if (chunk.characterSpans.length > 0) {
221225
const candidateParts = getWordSpans(candidate, stringToWordSpans);
222226
const isCaseSensitive = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ false) ? true
223-
: tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ true) ? false : undefined;
227+
: tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ true) ? false : undefined;
224228
if (isCaseSensitive !== undefined) {
225229
return createPatternMatch(PatternMatchKind.camelCase, isCaseSensitive);
226230
}
227231
}
228232
}
229-
230-
if (isLowercase) {
231-
// f) Is the pattern a substring of the candidate starting on one of the candidate's word boundaries?
232-
233-
// We could check every character boundary start of the candidate for the pattern. However, that's
234-
// an m * n operation in the wost case. Instead, find the first instance of the pattern
235-
// substring, and see if it starts on a capital letter. It seems unlikely that the user will try to
236-
// filter the list based on a substring that starts on a capital letter and also with a lowercase one.
237-
// (Pattern: fogbar, Candidate: quuxfogbarFogBar).
238-
if (chunk.text.length < candidate.length) {
239-
if (index > 0 && isUpperCaseLetter(candidate.charCodeAt(index))) {
240-
return createPatternMatch(PatternMatchKind.substring, /*isCaseSensitive:*/ false);
241-
}
242-
}
243-
}
244-
245-
return undefined;
246233
}
247234

248235
function containsSpaceOrAsterisk(text: string): boolean {
@@ -287,24 +274,26 @@ namespace ts {
287274
// b) Check if the word is a prefix of the candidate, in a case insensitive or
288275
// sensitive manner. If it does, return that there was a prefix match.
289276
//
290-
// c) If the word is entirely lowercase, then check if it is contained anywhere in the
291-
// candidate in a case insensitive manner. If so, return that there was a substring
292-
// match.
277+
// If the word is entirely lowercase:
278+
// c) Then check if it is contained anywhere in the
279+
// candidate in a case insensitive manner. If so, return that there was a substring
280+
// match.
293281
//
294-
// Note: We only have a substring match if the lowercase part is prefix match of
295-
// some word part. That way we don't match something like 'Class' when the user
296-
// types 'a'. But we would match 'FooAttribute' (since 'Attribute' starts with
297-
// 'a').
282+
// Note: We only have a substring match if the lowercase part is prefix match of
283+
// some word part. That way we don't match something like 'Class' when the user
284+
// types 'a'. But we would match 'FooAttribute' (since 'Attribute' starts with
285+
// 'a').
298286
//
299-
// d) If the word was not entirely lowercase, then check if it is contained in the
300-
// candidate in a case *sensitive* manner. If so, return that there was a substring
301-
// match.
287+
// d) The word is all lower case. Is it a case insensitive substring of the candidate starting
288+
// on a part boundary of the candidate?
302289
//
303-
// e) If the word was not entirely lowercase, then attempt a camel cased match as
304-
// well.
290+
// Else:
291+
// e) If the word was not entirely lowercase, then check if it is contained in the
292+
// candidate in a case *sensitive* manner. If so, return that there was a substring
293+
// match.
305294
//
306-
// f) The word is all lower case. Is it a case insensitive substring of the candidate starting
307-
// on a part boundary of the candidate?
295+
// f) If the word was not entirely lowercase, then attempt a camel cased match as
296+
// well.
308297
//
309298
// Only if all words have some sort of match is the pattern considered matched.
310299

0 commit comments

Comments
 (0)