add supports of completion label list (#20362)

This commit is contained in:
wenlu.wang 2017-12-06 23:01:37 +08:00 committed by Andy
parent 3a3bb8e3f0
commit ae25d09761
2 changed files with 87 additions and 0 deletions

View file

@ -39,6 +39,11 @@ namespace ts.Completions {
return getStringLiteralCompletionEntries(sourceFile, position, typeChecker, compilerOptions, host, log);
}
const contextToken = findPrecedingToken(position, sourceFile);
if (isInBreakOrContinue(contextToken)) {
return getLabelCompletionAtPosition(contextToken);
}
const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, options, compilerOptions.target);
if (!completionData) {
return undefined;
@ -223,6 +228,18 @@ namespace ts.Completions {
return uniques;
}
function isInBreakOrContinue(contextToken: Node): boolean {
return contextToken && isBreakOrContinueStatement(contextToken.parent) &&
(contextToken.kind === SyntaxKind.BreakKeyword || contextToken.kind === SyntaxKind.ContinueKeyword || contextToken.kind === SyntaxKind.Identifier);
}
function getLabelCompletionAtPosition(contextToken: Node): CompletionInfo | undefined {
const entries = getLabelStatementCompletions(contextToken.parent);
if (entries.length) {
return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries };
}
}
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost, log: Log): CompletionInfo | undefined {
const node = findPrecedingToken(position, sourceFile);
if (!node || node.kind !== SyntaxKind.StringLiteral) {
@ -358,6 +375,32 @@ namespace ts.Completions {
return undefined;
}
function getLabelStatementCompletions(node: Node): CompletionEntry[] {
const entries: CompletionEntry[] = [];
const uniques = createMap<true>();
let current = node;
while (current) {
if (isFunctionLike(current)) {
break;
}
if (isLabeledStatement(current)) {
const name = current.label.text;
if (!uniques.has(name)) {
uniques.set(name, true);
entries.push({
name,
kindModifiers: ScriptElementKindModifier.none,
kind: ScriptElementKind.label,
sortText: "0"
});
}
}
current = current.parent;
}
return entries;
}
function addStringLiteralCompletionsFromType(type: Type, result: Push<CompletionEntry>, typeChecker: TypeChecker, uniques = createMap<true>()): void {
if (type && type.flags & TypeFlags.TypeParameter) {
type = typeChecker.getBaseConstraintOfType(type);

View file

@ -0,0 +1,44 @@
/// <reference path="fourslash.ts"/>
//// label: while (true) {
//// break /*1*/
//// continue /*2*/
//// testlabel: while (true) {
//// break /*3*/
//// continue /*4*/
//// break tes/*5*/
//// continue tes/*6*/
//// }
//// break /*7*/
//// break; /*8*/
////}
goTo.marker("1");
verify.completionListContains("label");
goTo.marker("2");
verify.completionListContains("label");
verify.not.completionListContains("testlabel");
goTo.marker("3");
verify.completionListContains("label");
verify.completionListContains("testlabel");
goTo.marker("4");
verify.completionListContains("label");
verify.completionListContains("testlabel");
goTo.marker("5");
verify.completionListContains("testlabel");
verify.completionListContains("label");
goTo.marker("6");
verify.completionListContains("testlabel");
verify.completionListContains("label");
goTo.marker("7");
verify.completionListContains("label");
verify.not.completionListContains("testlabel");
goTo.marker("8");
verify.not.completionListContains("label");