Add 'triggerCharacter' option for completions requests (#23491)

* Add 'triggerCharacter' option for completions requests

* mhegazy code review

* More code review

* Handle '<' in comment
This commit is contained in:
Andy
2018-04-20 10:25:58 -07:00
committed by GitHub
parent 2826bc72b8
commit 22f2b118b7
11 changed files with 85 additions and 6 deletions
+3
View File
@@ -842,6 +842,7 @@ namespace FourSlash {
const actualCompletions = this.getCompletionListAtCaret(options);
if (!actualCompletions) {
if (expected === undefined) return;
this.raiseError(`No completions at position '${this.currentCaretPosition}'.`);
}
@@ -4653,10 +4654,12 @@ namespace FourSlashInterface {
export type ExpectedCompletionEntry = string | { name: string, insertText?: string, replacementSpan?: FourSlash.Range };
export interface CompletionsAtOptions extends Partial<ts.UserPreferences> {
triggerCharacter?: string;
isNewIdentifierLocation?: boolean;
}
export interface VerifyCompletionListContainsOptions extends ts.UserPreferences {
triggerCharacter?: string;
sourceDisplay: string;
isRecommended?: true;
insertText?: string;
+1
View File
@@ -1749,6 +1749,7 @@ namespace ts.server.protocol {
* Optional prefix to apply to possible completions.
*/
prefix?: string;
triggerCharacter?: string;
/**
* @deprecated Use UserPreferences.includeCompletionsForModuleExports
*/
+1
View File
@@ -1287,6 +1287,7 @@ namespace ts.server {
const completions = project.getLanguageService().getCompletionsAtPosition(file, position, {
...this.getPreferences(file),
triggerCharacter: args.triggerCharacter,
includeExternalModuleExports: args.includeExternalModuleExports,
includeInsertTextCompletions: args.includeInsertTextCompletions
});
+29 -1
View File
@@ -25,7 +25,7 @@ namespace ts.Completions {
const enum GlobalsSearch { Continue, Success, Fail }
export function getCompletionsAtPosition(host: LanguageServiceHost, program: Program, log: Log, sourceFile: SourceFile, position: number, preferences: UserPreferences): CompletionInfo | undefined {
export function getCompletionsAtPosition(host: LanguageServiceHost, program: Program, log: Log, sourceFile: SourceFile, position: number, preferences: UserPreferences, triggerCharacter: string | undefined): CompletionInfo | undefined {
const typeChecker = program.getTypeChecker();
const compilerOptions = program.getCompilerOptions();
if (isInReferenceComment(sourceFile, position)) {
@@ -34,6 +34,7 @@ namespace ts.Completions {
}
const contextToken = findPrecedingToken(position, sourceFile);
if (triggerCharacter && !isValidTrigger(sourceFile, triggerCharacter, contextToken, position)) return undefined;
if (isInString(sourceFile, position, contextToken)) {
return !contextToken || !isStringLiteralLike(contextToken)
@@ -2197,4 +2198,31 @@ namespace ts.Completions {
function hasIndexSignature(type: Type): boolean {
return !!type.getStringIndexType() || !!type.getNumberIndexType();
}
function isValidTrigger(sourceFile: SourceFile, triggerCharacter: string, contextToken: Node, position: number): boolean {
switch (triggerCharacter) {
case '"':
case "'":
case "`":
// Only automatically bring up completions if this is an opening quote.
return isStringLiteralOrTemplate(contextToken) && position === contextToken.getStart(sourceFile) + 1;
case "<":
// Opening JSX tag
return contextToken.kind === SyntaxKind.LessThanToken && contextToken.parent.kind !== SyntaxKind.BinaryExpression;
default:
return Debug.fail(triggerCharacter);
}
}
function isStringLiteralOrTemplate(node: Node): node is StringLiteralLike | TemplateExpression | TaggedTemplateExpression {
switch (node.kind) {
case SyntaxKind.StringLiteral:
case SyntaxKind.NoSubstitutionTemplateLiteral:
case SyntaxKind.TemplateExpression:
case SyntaxKind.TaggedTemplateExpression:
return true;
default:
return false;
}
}
}
+2 -1
View File
@@ -1409,7 +1409,8 @@ namespace ts {
log,
getValidSourceFile(fileName),
position,
fullPreferences);
fullPreferences,
options.triggerCharacter);
}
function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions: FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences = defaultPreferences): CompletionEntryDetails {
+1 -1
View File
@@ -912,7 +912,7 @@ namespace ts {
* to provide at the given source position and providing a member completion
* list if requested.
*/
public getCompletionsAtPosition(fileName: string, position: number, preferences: UserPreferences | undefined) {
public getCompletionsAtPosition(fileName: string, position: number, preferences: GetCompletionsAtPositionOptions | undefined) {
return this.forwardJSONCall(
`getCompletionsAtPosition('${fileName}', ${position}, ${preferences})`,
() => this.languageService.getCompletionsAtPosition(fileName, position, preferences)
+2 -1
View File
@@ -354,8 +354,9 @@ namespace ts {
export type OrganizeImportsScope = CombinedCodeFixScope;
/** @deprecated Use UserPreferences */
export interface GetCompletionsAtPositionOptions extends UserPreferences {
/** If the editor is asking for completions because a certain character was typed, and not because the user explicitly requested them, this should be set. */
triggerCharacter?: string;
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
/** @deprecated Use includeCompletionsWithInsertText */
+3 -1
View File
@@ -4455,8 +4455,9 @@ declare namespace ts {
fileName: string;
}
type OrganizeImportsScope = CombinedCodeFixScope;
/** @deprecated Use UserPreferences */
interface GetCompletionsAtPositionOptions extends UserPreferences {
/** If the editor is asking for completions because a certain character was typed, and not because the user explicitly requested them, this should be set. */
triggerCharacter?: string;
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
/** @deprecated Use includeCompletionsWithInsertText */
@@ -6667,6 +6668,7 @@ declare namespace ts.server.protocol {
* Optional prefix to apply to possible completions.
*/
prefix?: string;
triggerCharacter?: string;
/**
* @deprecated Use UserPreferences.includeCompletionsForModuleExports
*/
+2 -1
View File
@@ -4455,8 +4455,9 @@ declare namespace ts {
fileName: string;
}
type OrganizeImportsScope = CombinedCodeFixScope;
/** @deprecated Use UserPreferences */
interface GetCompletionsAtPositionOptions extends UserPreferences {
/** If the editor is asking for completions because a certain character was typed, and not because the user explicitly requested them, this should be set. */
triggerCharacter?: string;
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
/** @deprecated Use includeCompletionsWithInsertText */
@@ -0,0 +1,39 @@
/// <reference path="fourslash.ts" />
// @jsx: preserve
////const x: "a" | "b" = "/*openQuote*/"/*closeQuote*/;
////const y: 'a' | 'b' = '/*openSingleQuote*/'/*closeSingleQuote*/;
////const z: 'a' | 'b' = `/*openTemplate*/`/*closeTemplate*/;
////const q: "`a`" | "`b`" = "`/*openTemplateInQuote*/a`/*closeTemplateInQuote*/";
////// "/*quoteInComment*/ </*lessInComment*/
// @Filename: /a.tsx
////declare namespace JSX {
//// interface Element {}
//// interface IntrinsicElements {
//// div: {};
//// }
////}
////const ctr = </*openTag*/
////const less = 1 </*lessThan*/
verify.completionsAt("openQuote", ["a", "b"], { triggerCharacter: '"' });
verify.completionsAt("closeQuote", undefined, { triggerCharacter: '"' });
verify.completionsAt("openSingleQuote", ["a", "b"], { triggerCharacter: "'" });
verify.completionsAt("closeSingleQuote", undefined, { triggerCharacter: "'" });
verify.completionsAt("openTemplate", ["a", "b"], { triggerCharacter: "`" });
verify.completionsAt("closeTemplate", undefined, { triggerCharacter: "`" });
verify.completionsAt("openTemplateInQuote", undefined, { triggerCharacter: '`' });
verify.completionsAt("closeTemplateInQuote", undefined, { triggerCharacter: '`' });
verify.completionsAt("quoteInComment", undefined, { triggerCharacter: '"' });
verify.completionsAt("lessInComment", undefined, { triggerCharacter: "<" });
goTo.marker("openTag");
verify.completionListContains("div", undefined, undefined, undefined, undefined, undefined, { triggerCharacter: "<" });
verify.completionsAt("lessThan", undefined, { triggerCharacter: "<" });
+2
View File
@@ -157,6 +157,7 @@ declare namespace FourSlashInterface {
spanIndex?: number,
hasAction?: boolean,
options?: UserPreferences & {
triggerCharacter?: string,
sourceDisplay?: string,
isRecommended?: true,
insertText?: string,
@@ -530,6 +531,7 @@ declare namespace FourSlashInterface {
importModuleSpecifierPreference?: "relative" | "non-relative";
}
interface CompletionsAtOptions extends UserPreferences {
triggerCharacter?: string;
isNewIdentifierLocation?: boolean;
}
}