From d186c8311903dec4e88e0e3d8d09688a9c72d9da Mon Sep 17 00:00:00 2001 From: Jason Ramsay Date: Mon, 3 Oct 2016 16:29:06 -0700 Subject: [PATCH] Add isGlobalCompletion to CompletionInfo for snippet injection --- src/harness/fourslash.ts | 14 +++++++ src/server/client.ts | 1 + src/services/completions.ts | 25 +++++++---- src/services/types.ts | 1 + .../completionListIsGlobalCompletion.ts | 42 +++++++++++++++++++ 5 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 tests/cases/fourslash/completionListIsGlobalCompletion.ts diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0b4418b123..9e20e8a36d 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -754,6 +754,16 @@ namespace FourSlash { } } + public verifyCompletionListIsGlobal(expected: boolean) { + const completions = this.getCompletionListAtCaret(); + if (!completions && expected !== undefined) { + this.raiseError(`verifyCompletionListIsGlobal failed - expected result to be ${completions}`); + } + else if (completions && completions.isGlobalCompletion !== expected) { + this.raiseError(`verifyCompletionListIsGlobal failed - expected result to be ${completions.isGlobalCompletion}`); + } + } + public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) { const completions = this.getCompletionListAtCaret(); if (completions) { @@ -3046,6 +3056,10 @@ namespace FourSlashInterface { this.state.verifyCompletionListIsEmpty(this.negative); } + public completionListIsGlobal(expected: boolean) { + this.state.verifyCompletionListIsGlobal(expected); + } + public completionListAllowsNewIdentifier() { this.state.verifyCompletionListAllowsNewIdentifier(this.negative); } diff --git a/src/server/client.ts b/src/server/client.ts index 5032056c2f..688408dfb8 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -214,6 +214,7 @@ namespace ts.server { const response = this.processResponse(request); return { + isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: response.body.map(entry => { diff --git a/src/services/completions.ts b/src/services/completions.ts index a43717921c..78756c1ac4 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -14,11 +14,11 @@ namespace ts.Completions { return undefined; } - const { symbols, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData; + const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isJsDocTagName } = completionData; if (isJsDocTagName) { // If the current position is a jsDoc tag name, only tag names should be provided for completion - return { isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() }; + return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getAllJsDocCompletionEntries() }; } const entries: CompletionEntry[] = []; @@ -56,7 +56,7 @@ namespace ts.Completions { addRange(entries, keywordCompletions); } - return { isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, entries }; + return { isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation: isNewIdentifierLocation, entries }; function getJavaScriptCompletionEntries(sourceFile: SourceFile, position: number, uniqueNames: Map): CompletionEntry[] { const entries: CompletionEntry[] = []; @@ -190,7 +190,7 @@ namespace ts.Completions { if (type) { getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, element, /*performCharacterChecks*/false); if (entries.length) { - return { isMemberCompletion: true, isNewIdentifierLocation: true, entries }; + return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries }; } } } @@ -209,7 +209,7 @@ namespace ts.Completions { } if (entries.length) { - return { isMemberCompletion: false, isNewIdentifierLocation: true, entries }; + return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: true, entries }; } return undefined; @@ -221,7 +221,7 @@ namespace ts.Completions { if (type) { getCompletionEntriesFromSymbols(type.getApparentProperties(), entries, node, /*performCharacterChecks*/false); if (entries.length) { - return { isMemberCompletion: true, isNewIdentifierLocation: true, entries }; + return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: true, entries }; } } return undefined; @@ -233,7 +233,7 @@ namespace ts.Completions { const entries: CompletionEntry[] = []; addStringLiteralCompletionsFromType(type, entries); if (entries.length) { - return { isMemberCompletion: false, isNewIdentifierLocation: false, entries }; + return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries }; } } return undefined; @@ -281,6 +281,7 @@ namespace ts.Completions { entries = getCompletionEntriesForNonRelativeModules(literalValue, scriptDirectory, span); } return { + isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: true, entries @@ -558,6 +559,7 @@ namespace ts.Completions { } return { + isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: true, entries @@ -812,7 +814,7 @@ namespace ts.Completions { } if (isJsDocTagName) { - return { symbols: undefined, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName }; + return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, isJsDocTagName }; } if (!insideJsDocTagExpression) { @@ -884,6 +886,7 @@ namespace ts.Completions { } const semanticStart = timestamp(); + let isGlobalCompletion: boolean; let isMemberCompletion: boolean; let isNewIdentifierLocation: boolean; let symbols: Symbol[] = []; @@ -899,6 +902,7 @@ namespace ts.Completions { else { symbols = tagSymbols; } + isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; } @@ -909,6 +913,7 @@ namespace ts.Completions { if (!typeChecker.isUnknownSymbol(tagSymbol)) { symbols = [tagSymbol]; } + isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; } @@ -919,14 +924,16 @@ namespace ts.Completions { if (!tryGetGlobalSymbols()) { return undefined; } + isGlobalCompletion = true; } log("getCompletionData: Semantic work: " + (timestamp() - semanticStart)); - return { symbols, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName }; + return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), isJsDocTagName }; function getTypeScriptMemberSymbols(): void { // Right of dot member completion list + isGlobalCompletion = false; isMemberCompletion = true; isNewIdentifierLocation = false; diff --git a/src/services/types.ts b/src/services/types.ts index 874d96fccc..f84986bb53 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -503,6 +503,7 @@ namespace ts { } export interface CompletionInfo { + isGlobalCompletion: boolean; isMemberCompletion: boolean; isNewIdentifierLocation: boolean; // true when the current location also allows for a new identifier entries: CompletionEntry[]; diff --git a/tests/cases/fourslash/completionListIsGlobalCompletion.ts b/tests/cases/fourslash/completionListIsGlobalCompletion.ts new file mode 100644 index 0000000000..58107cbcb7 --- /dev/null +++ b/tests/cases/fourslash/completionListIsGlobalCompletion.ts @@ -0,0 +1,42 @@ +/// + +/////// // no globals in reference paths +////import { /*2*/ } from "./file.ts"; // no globals in imports +////var test = "/*3*/"; // no globals in strings +/////*4*/class A { // insert globals +//// foo(): string { return ''; } +////} +//// +////class /*5*/B extends A { // no globals after class keyword +//// bar(): string { +//// /*6*/ // insert globals +//// return ''; +//// } +////} +//// +////class C { // no globals at beginning of generics +//// x: U; +//// y = this./*8*/x; // no globals inserted for member completions +//// /*9*/ // insert globals +////} +/////*10*/ // insert globals +goTo.marker("1"); +verify.completionListIsGlobal(false); +goTo.marker("2"); +verify.completionListIsGlobal(undefined); +goTo.marker("3"); +verify.completionListIsGlobal(undefined); +goTo.marker("4"); +verify.completionListIsGlobal(true); +goTo.marker("5"); +verify.completionListIsGlobal(undefined); +goTo.marker("6"); +verify.completionListIsGlobal(true); +goTo.marker("7"); +verify.completionListIsGlobal(undefined); +goTo.marker("8"); +verify.completionListIsGlobal(false); +goTo.marker("9"); +verify.completionListIsGlobal(true); +goTo.marker("10"); +verify.completionListIsGlobal(true);