Skip to content

Commit ee9998e

Browse files
committed
add supports of completion label list
1 parent cdd3cd4 commit ee9998e

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

src/services/completions.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ namespace ts.Completions {
3939
return getStringLiteralCompletionEntries(sourceFile, position, typeChecker, compilerOptions, host, log);
4040
}
4141

42+
if (isInBreakOrContinue(sourceFile, position)) {
43+
return getLabelCompletionAtPosition(sourceFile, position);
44+
}
45+
4246
const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, options, compilerOptions.target);
4347
if (!completionData) {
4448
return undefined;
@@ -211,6 +215,19 @@ namespace ts.Completions {
211215
return uniques;
212216
}
213217

218+
function getLabelCompletionAtPosition(sourceFile: SourceFile, position: number): CompletionInfo | undefined {
219+
const contextToken: Node = findPrecedingToken(position, sourceFile);
220+
if (!contextToken || !contextToken.parent || !isBreakOrContinueStatement(contextToken.parent)) {
221+
return undefined;
222+
}
223+
const entries: CompletionEntry[] = [];
224+
addLabelStatementCompletions(contextToken.parent, entries);
225+
226+
if (entries.length) {
227+
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries };
228+
}
229+
}
230+
214231
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, log: Log): CompletionInfo | undefined {
215232
const node = findPrecedingToken(position, sourceFile);
216233
if (!node || node.kind !== SyntaxKind.StringLiteral) {
@@ -346,6 +363,28 @@ namespace ts.Completions {
346363
return undefined;
347364
}
348365

366+
function addLabelStatementCompletions(node: Node, entries: CompletionEntry[], uniques = createMap<true>()): void {
367+
let current: Node = node;
368+
while (current) {
369+
if (isFunctionLike(current)) {
370+
break;
371+
}
372+
if (isLabeledStatement(current)) {
373+
const name = current.label.escapedText as string;
374+
if (!uniques.has(name)) {
375+
uniques.set(name, true);
376+
entries.push({
377+
name,
378+
kindModifiers: ScriptElementKindModifier.none,
379+
kind: ScriptElementKind.label,
380+
sortText: "0"
381+
});
382+
}
383+
}
384+
current = current.parent;
385+
}
386+
}
387+
349388
function addStringLiteralCompletionsFromType(type: Type, result: Push<CompletionEntry>, typeChecker: TypeChecker, uniques = createMap<true>()): void {
350389
if (type && type.flags & TypeFlags.TypeParameter) {
351390
type = typeChecker.getBaseConstraintOfType(type);

src/services/utilities.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -857,6 +857,11 @@ namespace ts {
857857
return false;
858858
}
859859

860+
export function isInBreakOrContinue(sourceFile: SourceFile, position: number): boolean {
861+
const contextToken = findPrecedingToken(position, sourceFile);
862+
return contextToken && contextToken.parent && isBreakOrContinueStatement(contextToken.parent);
863+
}
864+
860865
/**
861866
* returns true if the position is in between the open and close elements of an JSX expression.
862867
*/
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/// <reference path="fourslash.ts"/>
2+
3+
//// label: while (true) {
4+
//// break /*1*/
5+
//// continue /*2*/
6+
//// testlabel: while (true) {
7+
//// break /*3*/
8+
//// continue /*4*/
9+
//// break tes/*5*/
10+
//// continue tes/*6*/
11+
//// }
12+
//// break /*7*/
13+
//// break; /*8*/
14+
////}
15+
16+
goTo.marker("1");
17+
verify.completionListContains("label");
18+
19+
goTo.marker("2");
20+
verify.completionListContains("label");
21+
verify.not.completionListContains("testlabel");
22+
23+
goTo.marker("3");
24+
verify.completionListContains("label");
25+
verify.completionListContains("testlabel");
26+
27+
goTo.marker("4");
28+
verify.completionListContains("label");
29+
verify.completionListContains("testlabel");
30+
31+
goTo.marker("5");
32+
verify.completionListContains("testlabel");
33+
verify.completionListContains("label");
34+
35+
goTo.marker("6");
36+
verify.completionListContains("testlabel");
37+
verify.completionListContains("label");
38+
39+
goTo.marker("7");
40+
verify.completionListContains("label");
41+
verify.not.completionListContains("testlabel");
42+
43+
goTo.marker("8");
44+
verify.not.completionListContains("label");

0 commit comments

Comments
 (0)