Skip to content

Commit 4b271d2

Browse files
Address code review feedback.
1 parent 8d7791c commit 4b271d2

3 files changed

Lines changed: 164 additions & 153 deletions

File tree

Jakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ var servicesSources = [
6565
return path.join(compilerDirectory, f);
6666
}).concat([
6767
"breakpoints.ts",
68+
"navigateTo.ts",
6869
"navigationBar.ts",
6970
"outliningElementsCollector.ts",
7071
"services.ts",

src/services/navigateTo.ts

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
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 }));
17+
18+
var rawItems: RawNavigateToItem[] = [];
19+
20+
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
21+
forEach(program.getSourceFiles(), sourceFile => {
22+
cancellationToken.throwIfCancellationRequested();
23+
24+
var fileName = sourceFile.fileName;
25+
var declarations = sourceFile.getNamedDeclarations();
26+
for (var i = 0, n = declarations.length; i < n; i++) {
27+
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 });
33+
}
34+
}
35+
});
36+
37+
rawItems.sort((i1, i2) => i1.matchKind - i2.matchKind);
38+
if (maxResultCount !== undefined) {
39+
rawItems = rawItems.slice(0, maxResultCount);
40+
}
41+
42+
var items = map(rawItems, createNavigateToItem);
43+
44+
return items;
45+
46+
function createNavigateToItem(rawItem: RawNavigateToItem): NavigateToItem {
47+
var declaration = rawItem.declaration;
48+
var container = <Declaration>getContainerNode(declaration);
49+
return {
50+
name: rawItem.name,
51+
kind: getNodeKind(declaration),
52+
kindModifiers: getNodeModifiers(declaration),
53+
matchKind: MatchKind[rawItem.matchKind],
54+
fileName: rawItem.fileName,
55+
textSpan: createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()),
56+
// TODO(jfreeman): What should be the containerName when the container has a computed name?
57+
containerName: container && container.name ? (<Identifier>container.name).text : "",
58+
containerKind: container && container.name ? getNodeKind(container) : ""
59+
};
60+
}
61+
62+
function hasAnyUpperCaseCharacter(s: string): boolean {
63+
for (var i = 0, n = s.length; i < n; i++) {
64+
var c = s.charCodeAt(i);
65+
if ((CharacterCodes.A <= c && c <= CharacterCodes.Z) ||
66+
(c >= CharacterCodes.maxAsciiCharacter && s.charAt(i).toLocaleLowerCase() !== s.charAt(i))) {
67+
return true;
68+
}
69+
}
70+
71+
return false;
72+
}
73+
74+
function getMatchKind(searchTerms: { caseSensitive: boolean; term: string }[], name: string): MatchKind {
75+
var matchKind = MatchKind.none;
76+
77+
if (name) {
78+
for (var j = 0, n = searchTerms.length; j < n; j++) {
79+
var searchTerm = searchTerms[j];
80+
var nameToSearch = searchTerm.caseSensitive ? name : name.toLocaleLowerCase();
81+
// in case of case-insensitive search searchTerm.term will already be lower-cased
82+
var index = nameToSearch.indexOf(searchTerm.term);
83+
if (index < 0) {
84+
// Didn't match.
85+
return MatchKind.none;
86+
}
87+
88+
var termKind = MatchKind.substring;
89+
if (index === 0) {
90+
// here we know that match occur at the beginning of the string.
91+
// 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
92+
termKind = name.length === searchTerm.term.length ? MatchKind.exact : MatchKind.prefix;
93+
}
94+
95+
// Update our match kind if we don't have one, or if this match is better.
96+
if (matchKind === MatchKind.none || termKind < matchKind) {
97+
matchKind = termKind;
98+
}
99+
}
100+
}
101+
102+
return matchKind;
103+
}
104+
}
105+
}

src/services/services.ts

Lines changed: 58 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
/// <reference path='breakpoints.ts' />
44
/// <reference path='outliningElementsCollector.ts' />
5+
/// <reference path='navigateTo.ts' />
56
/// <reference path='navigationBar.ts' />
67
/// <reference path='signatureHelp.ts' />
78
/// <reference path='utilities.ts' />
@@ -1378,13 +1379,6 @@ module ts {
13781379
public static typeAlias = "type alias name";
13791380
}
13801381

1381-
enum MatchKind {
1382-
none = 0,
1383-
exact = 1,
1384-
prefix = 2,
1385-
substring = 3,
1386-
}
1387-
13881382
/// Language Service
13891383

13901384
interface CompletionSession {
@@ -1992,6 +1986,62 @@ module ts {
19921986
});
19931987
}
19941988

1989+
/* @internal */ export function getContainerNode(node: Node): Node {
1990+
while (true) {
1991+
node = node.parent;
1992+
if (!node) {
1993+
return undefined;
1994+
}
1995+
switch (node.kind) {
1996+
case SyntaxKind.SourceFile:
1997+
case SyntaxKind.MethodDeclaration:
1998+
case SyntaxKind.MethodSignature:
1999+
case SyntaxKind.FunctionDeclaration:
2000+
case SyntaxKind.FunctionExpression:
2001+
case SyntaxKind.GetAccessor:
2002+
case SyntaxKind.SetAccessor:
2003+
case SyntaxKind.ClassDeclaration:
2004+
case SyntaxKind.InterfaceDeclaration:
2005+
case SyntaxKind.EnumDeclaration:
2006+
case SyntaxKind.ModuleDeclaration:
2007+
return node;
2008+
}
2009+
}
2010+
}
2011+
2012+
/* @internal */ export function getNodeKind(node: Node): string {
2013+
switch (node.kind) {
2014+
case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement;
2015+
case SyntaxKind.ClassDeclaration: return ScriptElementKind.classElement;
2016+
case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement;
2017+
case SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement;
2018+
case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement;
2019+
case SyntaxKind.VariableDeclaration:
2020+
return isConst(node)
2021+
? ScriptElementKind.constElement
2022+
: isLet(node)
2023+
? ScriptElementKind.letElement
2024+
: ScriptElementKind.variableElement;
2025+
case SyntaxKind.FunctionDeclaration: return ScriptElementKind.functionElement;
2026+
case SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement;
2027+
case SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement;
2028+
case SyntaxKind.MethodDeclaration:
2029+
case SyntaxKind.MethodSignature:
2030+
return ScriptElementKind.memberFunctionElement;
2031+
case SyntaxKind.PropertyDeclaration:
2032+
case SyntaxKind.PropertySignature:
2033+
return ScriptElementKind.memberVariableElement;
2034+
case SyntaxKind.IndexSignature: return ScriptElementKind.indexSignatureElement;
2035+
case SyntaxKind.ConstructSignature: return ScriptElementKind.constructSignatureElement;
2036+
case SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement;
2037+
case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement;
2038+
case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement;
2039+
case SyntaxKind.EnumMember: return ScriptElementKind.variableElement;
2040+
case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
2041+
}
2042+
return ScriptElementKind.unknown;
2043+
}
2044+
19952045
export function createLanguageService(host: LanguageServiceHost, documentRegistry: DocumentRegistry = createDocumentRegistry()): LanguageService {
19962046
var syntaxTreeCache: SyntaxTreeCache = new SyntaxTreeCache(host);
19972047
var ruleProvider: formatting.RulesProvider;
@@ -2722,29 +2772,6 @@ module ts {
27222772
}
27232773
}
27242774

2725-
function getContainerNode(node: Node): Node {
2726-
while (true) {
2727-
node = node.parent;
2728-
if (!node) {
2729-
return undefined;
2730-
}
2731-
switch (node.kind) {
2732-
case SyntaxKind.SourceFile:
2733-
case SyntaxKind.MethodDeclaration:
2734-
case SyntaxKind.MethodSignature:
2735-
case SyntaxKind.FunctionDeclaration:
2736-
case SyntaxKind.FunctionExpression:
2737-
case SyntaxKind.GetAccessor:
2738-
case SyntaxKind.SetAccessor:
2739-
case SyntaxKind.ClassDeclaration:
2740-
case SyntaxKind.InterfaceDeclaration:
2741-
case SyntaxKind.EnumDeclaration:
2742-
case SyntaxKind.ModuleDeclaration:
2743-
return node;
2744-
}
2745-
}
2746-
}
2747-
27482775
// TODO(drosen): use contextual SemanticMeaning.
27492776
function getSymbolKind(symbol: Symbol, typeResolver: TypeChecker, location: Node): string {
27502777
var flags = symbol.getFlags();
@@ -2831,39 +2858,6 @@ module ts {
28312858
return ScriptElementKind.unknown;
28322859
}
28332860

2834-
function getNodeKind(node: Node): string {
2835-
switch (node.kind) {
2836-
case SyntaxKind.ModuleDeclaration: return ScriptElementKind.moduleElement;
2837-
case SyntaxKind.ClassDeclaration: return ScriptElementKind.classElement;
2838-
case SyntaxKind.InterfaceDeclaration: return ScriptElementKind.interfaceElement;
2839-
case SyntaxKind.TypeAliasDeclaration: return ScriptElementKind.typeElement;
2840-
case SyntaxKind.EnumDeclaration: return ScriptElementKind.enumElement;
2841-
case SyntaxKind.VariableDeclaration:
2842-
return isConst(node)
2843-
? ScriptElementKind.constElement
2844-
: isLet(node)
2845-
? ScriptElementKind.letElement
2846-
: ScriptElementKind.variableElement;
2847-
case SyntaxKind.FunctionDeclaration: return ScriptElementKind.functionElement;
2848-
case SyntaxKind.GetAccessor: return ScriptElementKind.memberGetAccessorElement;
2849-
case SyntaxKind.SetAccessor: return ScriptElementKind.memberSetAccessorElement;
2850-
case SyntaxKind.MethodDeclaration:
2851-
case SyntaxKind.MethodSignature:
2852-
return ScriptElementKind.memberFunctionElement;
2853-
case SyntaxKind.PropertyDeclaration:
2854-
case SyntaxKind.PropertySignature:
2855-
return ScriptElementKind.memberVariableElement;
2856-
case SyntaxKind.IndexSignature: return ScriptElementKind.indexSignatureElement;
2857-
case SyntaxKind.ConstructSignature: return ScriptElementKind.constructSignatureElement;
2858-
case SyntaxKind.CallSignature: return ScriptElementKind.callSignatureElement;
2859-
case SyntaxKind.Constructor: return ScriptElementKind.constructorImplementationElement;
2860-
case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement;
2861-
case SyntaxKind.EnumMember: return ScriptElementKind.variableElement;
2862-
case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement;
2863-
}
2864-
return ScriptElementKind.unknown;
2865-
}
2866-
28672861
function getSymbolModifiers(symbol: Symbol): string {
28682862
return symbol && symbol.declarations && symbol.declarations.length > 0
28692863
? getNodeModifiers(symbol.declarations[0])
@@ -4666,96 +4660,7 @@ module ts {
46664660
function getNavigateToItems(searchValue: string, maxResultCount?: number): NavigateToItem[] {
46674661
synchronizeHostData();
46684662

4669-
// Split search value in terms array
4670-
var terms = searchValue.split(" ");
4671-
4672-
// default NavigateTo approach: if search term contains only lower-case chars - use case-insensitive search, otherwise switch to case-sensitive version
4673-
var searchTerms = map(terms, t => ({ caseSensitive: hasAnyUpperCaseCharacter(t), term: t }));
4674-
4675-
var rawItems: { name: string; fileName: string; matchKind: MatchKind; declaration: Declaration }[] = [];
4676-
4677-
// Search the declarations in all files and output matched NavigateToItem into array of NavigateToItem[]
4678-
forEach(program.getSourceFiles(), sourceFile => {
4679-
cancellationToken.throwIfCancellationRequested();
4680-
4681-
var fileName = sourceFile.fileName;
4682-
var declarations = sourceFile.getNamedDeclarations();
4683-
for (var i = 0, n = declarations.length; i < n; i++) {
4684-
var declaration = declarations[i];
4685-
// TODO(jfreeman): Skip this declaration if it has a computed name
4686-
var name = (<Identifier>declaration.name).text;
4687-
var matchKind = getMatchKind(searchTerms, name);
4688-
if (matchKind !== MatchKind.none) {
4689-
rawItems.push({ name, fileName, matchKind, declaration });
4690-
}
4691-
}
4692-
});
4693-
4694-
rawItems.sort((i1, i2) => i1.matchKind - i2.matchKind);
4695-
if (maxResultCount !== undefined) {
4696-
rawItems = rawItems.slice(0, maxResultCount);
4697-
}
4698-
4699-
var items = map(rawItems, i => {
4700-
var declaration = i.declaration;
4701-
var container = <Declaration>getContainerNode(declaration);
4702-
return <NavigateToItem>{
4703-
name: i.name,
4704-
kind: getNodeKind(declaration),
4705-
kindModifiers: getNodeModifiers(declaration),
4706-
matchKind: MatchKind[i.matchKind],
4707-
fileName: i.fileName,
4708-
textSpan: createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()),
4709-
// TODO(jfreeman): What should be the containerName when the container has a computed name?
4710-
containerName: container && container.name ? (<Identifier>container.name).text : "",
4711-
containerKind: container && container.name ? getNodeKind(container) : ""
4712-
};
4713-
});
4714-
4715-
return items;
4716-
4717-
function hasAnyUpperCaseCharacter(s: string): boolean {
4718-
for (var i = 0, n = s.length; i < n; i++) {
4719-
var c = s.charCodeAt(i);
4720-
if ((CharacterCodes.A <= c && c <= CharacterCodes.Z) ||
4721-
(c >= CharacterCodes.maxAsciiCharacter && s.charAt(i).toLocaleLowerCase() !== s.charAt(i))) {
4722-
return true;
4723-
}
4724-
}
4725-
4726-
return false;
4727-
}
4728-
4729-
function getMatchKind(searchTerms: { caseSensitive: boolean; term: string }[], name: string): MatchKind {
4730-
var matchKind = MatchKind.none;
4731-
4732-
if (name) {
4733-
for (var j = 0, n = searchTerms.length; j < n; j++) {
4734-
var searchTerm = searchTerms[j];
4735-
var nameToSearch = searchTerm.caseSensitive ? name : name.toLocaleLowerCase();
4736-
// in case of case-insensitive search searchTerm.term will already be lower-cased
4737-
var index = nameToSearch.indexOf(searchTerm.term);
4738-
if (index < 0) {
4739-
// Didn't match.
4740-
return MatchKind.none;
4741-
}
4742-
4743-
var termKind = MatchKind.substring;
4744-
if (index === 0) {
4745-
// here we know that match occur at the beginning of the string.
4746-
// 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
4747-
termKind = name.length === searchTerm.term.length ? MatchKind.exact : MatchKind.prefix;
4748-
}
4749-
4750-
// Update our match kind if we don't have one, or if this match is better.
4751-
if (matchKind === MatchKind.none || termKind < matchKind) {
4752-
matchKind = termKind;
4753-
}
4754-
}
4755-
}
4756-
4757-
return matchKind;
4758-
}
4663+
return ts.NavigateTo.getNavigateToItems(program, cancellationToken, searchValue, maxResultCount);
47594664
}
47604665

47614666
function containErrors(diagnostics: Diagnostic[]): boolean {

0 commit comments

Comments
 (0)