8000 Move NavigateTo over to using the new pattern matcher. · ezhangle/TypeScript@fd1b587 · GitHub
[go: up one dir, main page]

Skip to content

Commit fd1b587

Browse files
Move NavigateTo over to using the new pattern matcher.
1 parent a2d0d59 commit fd1b587

18 files changed

+175
-139
lines changed

src/server/client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ module ts.server {
229229
kind: entry.kind,
230230
kindModifiers: entry.kindModifiers,
231231
matchKind: entry.matchKind,
232+
isCaseSensitive: entry.isCaseSensitive,
232233
fileName: fileName,
233234
textSpan: ts.createTextSpanFromBounds(start, end)
234235
};

src/server/protocol.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,11 @@ declare module ts.server.protocol {
707707
* exact, substring, or prefix.
708708
*/
709709
matchKind?: string;
710+
711+
/**
712+
* If this was a case sensitive or insensitive match.
713+
*/
714+
isCaseSensitive?: boolean;
710715

711716
/**
712717
* Optional modifiers for the kind (such as 'public').

src/services/navigateTo.ts

Lines changed: 80 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,42 @@
11
module ts.NavigateTo {
2-
type RawNavigateToItem = { name: string; fileName: string; matchKind: MatchKind; declaration: Declaration };
3-
4-
enum MatchKind {
5-
none = 0,
6-
exact = 1,
7-
substring = 2,
8-
prefix = 3
9-
}
10-
11-
export function getNavigateToItems(program: Program, cancellationToken: CancellationTokenObject, searchValue: string, maxResultCount: number): NavigateToItem[]{
12-
// Split search value in terms array
13-
var terms = searchValue.split(" ");
14-
15-
// default NavigateTo approach: if search term contains only lower-case chars - use case-insensitive search, otherwise switch to case-sensitive version
16-
var searchTerms = map(terms, t => ({ caseSensitive: hasAnyUpperCaseCharacter(t), term: t }));
2+
type RawNavigateToItem = { name: string; fileName: string; matchKind: PatternMatchKind; isCaseSensitive: boolean; declaration: Declaration };
173

4+
export function getNavigateToItems(program: Program, cancellationToken: CancellationTokenObject, searchValue: string, maxResultCount: number): NavigateToItem[] {
5+
var patternMatcher = createPatternMatcher(searchValue);
186
var rawItems: RawNavigateToItem[] = [];
197

208
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
219
forEach(program.getSourceFiles(), sourceFile => {
2210
cancellationToken.throwIfCancellationRequested();
2311

24-
var fileName = sourceFile.fileName;
2512
var declarations = sourceFile.getNamedDeclarations();
2613
for (var i = 0, n = declarations.length; i < n; i++) {
2714
var declaration = declarations[i];
28-
// TODO(jfreeman): Skip this declaration if it has a computed name
29-
var name = (<Identifier>declaration.name).text;
30-
var matchKind = getMatchKind(searchTerms, name);
31-
if (matchKind !== MatchKind.none) {
32-
rawItems.push({ name, fileName, matchKind, declaration });
15+
var name = getDeclarationName(declaration);
16+
if (name !== undefined) {
17+
18+
// First do a quick check to see if the name of the declaration matches the
19+
// last portion of the (possibly) dotted name they're searching for.
20+
var matches = patternMatcher.getMatchesForLastSegmentOfPattern(name);
21+
22+
if (!matches) {
23+
continue;
24+
}
25+
26+
// It was a match! If the pattern has dots in it, then also see if hte
27+
// declaration container matches as well.
28+
if (patternMatcher.patternContainsDots) {
29+
var containerName = getContainerName(getContainerNode(declaration));
30+
matches = patternMatcher.getMatches(name, containerName);
31+
32+
if (!matches) {
33+
continue;
34+
}
35+
}
36+
37+
var fileName = sourceFile.fileName;
38+
var matchKind = bestMatchKind(matches);
39+
rawItems.push({ name, fileName, matchKind, isCaseSensitive: isCaseSensitive(matches), declaration });
3340
}
3441
}
3542
});
@@ -43,6 +50,56 @@ module ts.NavigateTo {
4350

4451
return items;
4552

53+
function isCaseSensitive(matches: PatternMatch[]): boolean {
54+
Debug.assert(matches.length > 0);
55+
56+
// This is a case sensitive match, only if all the submatches were case sensitive.
57+
for (var i = 0, n = matches.length; i < n; i++) {
58+
if (!matches[i].isCaseSensitive) {
59+
return false;
60+
}
61+
}
62+
63+
return true;
64+
}
65+
66+
function getDeclarationName(declaration: Declaration): string {
67+
if (declaration.name.kind === SyntaxKind.Identifier ||
68+
declaration.name.kind === SyntaxKind.StringLiteral ||
69+
declaration.name.kind === SyntaxKind.NumericLiteral) {
70+
71+
return (<Identifier>declaration.name).text;
72+
}
73+
74+
return undefined;
75+
}
76+
77+
function getContainerName(declaration: Declaration): string {
78+
var name = getDeclarationName(declaration);
79+
if (name === undefined) {
80+
return undefined;
81+
}
82+
83+
var container = getContainerNode(declaration);
84+
return container && container.name
85+
? getContainerName(container) + "." + name
86+
: name;
87+
}
88+
89+
function bestMatchKind(matches: PatternMatch[]) {
90+
Debug.assert(matches.length > 0);
91+
var bestMatchKind = PatternMatchKind.camelCase;
92+
93+
for (var i = 0, n = matches.length; i < n; i++) {
94+
var kind = matches[i].kind;
95+
if (kind < bestMatchKind) {
96+
bestMatchKind = kind;
97+
}
98+
}
99+
100+
return bestMatchKind;
101+
}
102+
46103
// This means "compare in a case insensitive manner."
47104
var baseSensitivity: Intl.CollatorOptions = { sensitivity: "base" };
48105
function compareNavigateToItems(i1: RawNavigateToItem, i2: RawNavigateToItem) {
@@ -62,56 +119,14 @@ module ts.NavigateTo {
62119
name: rawItem.name,
63120
kind: getNodeKind(declaration),
64121
kindModifiers: getNodeModifiers(declaration),
65-
matchKind: MatchKind[rawItem.matchKind],
122+
matchKind: PatternMatchKind[rawItem.matchKind],
123+
isCaseSensitive: rawItem.isCaseSensitive,
66124
fileName: rawItem.fileName,
67125
textSpan: createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()),
68126
// TODO(jfreeman): What should be the containerName when the container has a computed name?
69127
containerName: container && container.name ? (<Identifier>container.name).text : "",
70128
containerKind: container && container.name ? getNodeKind(container) : ""
71129
};
72130
}
73-
74-
function hasAnyUpperCaseCharacter(s: string): boolean {
75-
for (var i = 0, n = s.length; i < n; i++) {
76-
var c = s.charCodeAt(i);
77-
if ((CharacterCodes.A <= c && c <= CharacterCodes.Z) ||
78-
(c >= CharacterCodes.maxAsciiCharacter && s.charAt(i).toLocaleLowerCase() !== s.charAt(i))) {
79-
return true;
80-
}
81-
}
82-
83-
return false;
84-
}
85-
86-
function getMatchKind(searchTerms: { caseSensitive: boolean; term: string }[], name: string): MatchKind {
87-
var matchKind = MatchKind.none;
88-
89-
if (name) {
90-
for (var j = 0, n = searchTerms.length; j < n; j++) {
91-
var searchTerm = searchTerms[j];
92-
var nameToSearch = searchTerm.caseSensitive ? name : name.toLocaleLowerCase();
93-
// in case of case-insensitive search searchTerm.term will already be lower-cased
94-
var index = nameToSearch.indexOf(searchTerm.term);
95-
if (index < 0) {
96-
// Didn't match.
97-
return MatchKind.none;
98-
}
99-
100-
var termKind = MatchKind.substring;
101-
if (index === 0) {
102-
// here we know that match occur at the beginning of the string.
103-
// if search term and declName has the same length - we have an exact match, otherwise declName have longer length and this will be prefix match
104-
termKind = name.length === searchTerm.term.length ? MatchKind.exact : MatchKind.prefix;
105-
}
106-
107-
// Update our match kind if we don't have one, or if this match is better.
108-
if (matchKind === MatchKind.none || termKind < matchKind) {
109-
matchKind = termKind;
110-
}
111-
}
112-
}
113-
114-
return matchKind;
115-
}
116131
}
117132
}

src/services/patternMatcher.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
module ts {
22
// Note(cyrusn): this enum is ordered from strongest match type to weakest match type.
33
export enum PatternMatchKind {
4-
Exact,
5-
Prefix,
6-
Substring,
7-
CamelCase
4+
exact,
5+
prefix,
6+
substring,
7+
camelCase
88
}
99

1010
// Information about a match made by the pattern matcher between a candidate and the
@@ -202,12 +202,12 @@ module ts {
202202
if (chunk.text.length === candidate.length) {
203203
// a) Check if the part matches the candidate entirely, in an case insensitive or
204204
// sensitive manner. If it does, return that there was an exact match.
205-
return createPatternMatch(PatternMatchKind.Exact, punctuationStripped, /*isCaseSensitive:*/ candidate === chunk.text);
205+
return createPatternMatch(PatternMatchKind.exact, punctuationStripped, /*isCaseSensitive:*/ candidate === chunk.text);
206206
}
207207
else {
208208
// b) Check if the part is a prefix of the candidate, in a case insensitive or sensitive
209209
// manner. If it does, return that there was a prefix match.
210-
return createPatternMatch(PatternMatchKind.Prefix, punctuationStripped, /*isCaseSensitive:*/ startsWith(candidate, chunk.text));
210+
return createPatternMatch(PatternMatchKind.prefix, punctuationStripped, /*isCaseSensitive:*/ startsWith(candidate, chunk.text));
211211
}
212212
}
213213

@@ -225,7 +225,7 @@ module ts {
225225
for (var i = 0, n = wordSpans.length; i < n; i++) {
226226
var span = wordSpans[i]
227227
if (partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ true)) {
228-
return createPatternMatch(PatternMatchKind.Substring, punctuationStripped,
228+
return createPatternMatch(PatternMatchKind.substring, punctuationStripped,
229229
/*isCaseSensitive:*/ partStartsWith(candidate, span, chunk.text, /*ignoreCase:*/ false));
230230
}
231231
}
@@ -236,7 +236,7 @@ module ts {
236236
// candidate in a case *sensitive* manner. If so, return that there was a substring
237237
// match.
238238
if (candidate.indexOf(chunk.text) > 0) {
239-
return createPatternMatch(PatternMatchKind.Substring, punctuationStripped, /*isCaseSensitive:*/ true);
239+
return createPatternMatch(PatternMatchKind.substring, punctuationStripped, /*isCaseSensitive:*/ true);
240240
}
241241
}
242242

@@ -246,12 +246,12 @@ module ts {
246246
var candidateParts = getWordSpans(candidate);
247247
var camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ false);
248248
if (camelCaseWeight !== undefined) {
249-
return createPatternMatch(PatternMatchKind.CamelCase, punctuationStripped, /*isCaseSensitive:*/ true, /*camelCaseWeight:*/ camelCaseWeight);
249+
return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, /*isCaseSensitive:*/ true, /*camelCaseWeight:*/ camelCaseWeight);
250250
}
251251

252252
camelCaseWeight = tryCamelCaseMatch(candidate, candidateParts, chunk, /*ignoreCase:*/ true);
253253
if (camelCaseWeight !== undefined) {
254-
return createPatternMatch(PatternMatchKind.CamelCase, punctuationStripped, /*isCaseSensitive:*/ false, /*camelCaseWeight:*/ camelCaseWeight);
254+
return createPatternMatch(PatternMatchKind.camelCase, punctuationStripped, /*isCaseSensitive:*/ false, /*camelCaseWeight:*/ camelCaseWeight);
255255
}
256256
}
257257
}
@@ -266,7 +266,7 @@ module ts {
266266
// (Pattern: fogbar, Candidate: quuxfogbarFogBar).
267267
if (chunk.text.length < candidate.length) {
268268
if (index > 0 && isUpperCaseLetter(candidate.charCodeAt(index))) {
269-
return createPatternMatch(PatternMatchKind.Substring, punctuationStripped, /*isCaseSensitive:*/ false);
269+
return createPatternMatch(PatternMatchKind.substring, punctuationStripped, /*isCaseSensitive:*/ false);
270270
}
271271
}
272272
}
@@ -508,7 +508,7 @@ module ts {
508508
}
509509

510510
function compareCamelCase(result1: PatternMatch, result2: PatternMatch) {
511-
if (result1.kind === PatternMatchKind.CamelCase && result2.kind === PatternMatchKind.CamelCase) {
511+
if (result1.kind === PatternMatchKind.camelCase && result2.kind === PatternMatchKind.camelCase) {
512512
// Swap the values here. If result1 has a higher weight, then we want it to come
513513
// first.
514514
return result2.camelCaseWeight - result1.camelCaseWeight;

src/services/services.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,7 @@ module ts {
970970
kind: string;
971971
kindModifiers: string;
972972
matchKind: string;
973+
isCaseSensitive: boolean;
973974
fileName: string;
974975
textSpan: TextSpan;
975976
containerName: string;
@@ -1986,7 +1987,7 @@ module ts {
19861987
});
19871988
}
19881989

1989-
/* @internal */ export function getContainerNode(node: Node): Node {
1990+
/* @internal */ export function getContainerNode(node: Node): Declaration {
19901991
while (true) {
19911992
node = node.parent;
19921993
if (!node) {
@@ -2004,7 +2005,7 @@ module ts {
20042005
case SyntaxKind.InterfaceDeclaration:
20052006
case SyntaxKind.EnumDeclaration:
20062007
case SyntaxKind.ModuleDeclaration:
2007-
return node;
2008+
return <Declaration>node;
20082009
}
20092010
}
20102011
}

tests/baselines/reference/APISample_compile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1597,6 +1597,7 @@ declare module "typescript" {
15971597
kind: string;
15981598
kindModifiers: string;
15991599
matchKind: string;
1600+
isCaseSensitive: boolean;
16001601
fileName: string;
16011602
textSpan: TextSpan;
16021603
containerName: string;

tests/baselines/reference/APISample_compile.types

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5178,6 +5178,9 @@ declare module "typescript" {
51785178
matchKind: string;
51795179
>matchKind : string
51805180

5181+
isCaseSensitive: boolean;
5182+
>isCaseSensitive : boolean
5183+
51815184
fileName: string;
51825185
>fileName : string
51835186

tests/baselines/reference/APISample_linter.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,7 @@ declare module "typescript" {
16281628
kind: string;
16291629
kindModifiers: string;
16301630
matchKind: string;
1631+
isCaseSensitive: boolean;
16311632
fileName: string;
16321633
textSpan: TextSpan;
16331634
containerName: string;

tests/baselines/reference/APISample_linter.types

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5324,6 +5324,9 @@ declare module "typescript" {
53245324
matchKind: string;
53255325
>matchKind : string
53265326

5327+
isCaseSensitive: boolean;
5328+
>isCaseSensitive : boolean
5329+
53275330
fileName: string;
53285331
>fileName : string
53295332

tests/baselines/reference/APISample_transform.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,7 @@ declare module "typescript" {
16291629
kind: string;
16301630
kindModifiers: string;
16311631
matchKind: string;
1632+
isCaseSensitive: boolean;
16321633
fileName: string;
16331634
textSpan: TextSpan;
16341635
containerName: string;

tests/baselines/reference/APISample_transform.types

Lines changed: 3 additions & 0 deletio F41A ns
Original file line numberDiff line numberDiff line change
@@ -5274,6 +5274,9 @@ declare module "typescript" {
52745274
matchKind: string;
52755275
>matchKind : string
52765276

5277+
isCaseSensitive: boolean;
5278+
>isCaseSensitive : boolean
5279+
52775280
fileName: string;
52785281
>fileName : string
52795282

tests/baselines/reference/APISample_watcher.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,7 @@ declare module "typescript" {
16661666
kind: string;
16671667
kindModifiers: string;
16681668
matchKind: string;
1669+
isCaseSensitive: boolean;
16691670
fileName: string;
16701671
textSpan: TextSpan;
16711672
containerName: string;

tests/baselines/reference/APISample_watcher.types

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5447,6 +5447,9 @@ declare module "typescript" {
54475447
matchKind: string;
54485448
>matchKind : string
54495449

5450+
isCaseSensitive: boolean;
5451+
>isCaseSensitive : boolean
5452+
54505453
fileName: string;
54515454
>fileName : string
54525455

tests/cases/fourslash/declareFunction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
goTo.marker();
66
//verify there is no empty navigation item.
7-
verify.navigationItemsListCount(0, "^$"/*empty string*/)
7+
verify.navigationItemsListCount(0, "")

0 commit comments

Comments
 (0)
0