[typescript-language-features] Support import statement completions for TypeScript 4.3 (#119009)

* Support import statement completions for TypeScript 4.3

* Fix forgotten argument

* Add snippet preference

Co-authored-by: Matt Bierner <matb@microsoft.com>
This commit is contained in:
Andrew Branch 2021-03-29 11:38:22 -07:00 committed by GitHub
parent 0854a0a623
commit 29ca249959
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 8 deletions

View file

@ -258,6 +258,24 @@
"description": "%configuration.suggest.includeAutomaticOptionalChainCompletions%",
"scope": "resource"
},
"javascript.suggest.includeCompletionsForImportStatements": {
"type": "boolean",
"default": true,
"description": "%configuration.suggest.includeCompletionsForImportStatements%",
"scope": "resource"
},
"typescript.suggest.includeCompletionsForImportStatements": {
"type": "boolean",
"default": true,
"description": "%configuration.suggest.includeCompletionsForImportStatements%",
"scope": "resource"
},
"typescript.suggest.includeCompletionsWithSnippetText": {
"type": "boolean",
"default": true,
"description": "%configuration.suggest.includeCompletionsWithSnippetText%",
"scope": "resource"
},
"typescript.reportStyleChecksAsWarnings": {
"type": "boolean",
"default": true,

View file

@ -5,6 +5,8 @@
"configuration.typescript": "TypeScript",
"configuration.suggest.completeFunctionCalls": "Complete functions with their parameter signature.",
"configuration.suggest.includeAutomaticOptionalChainCompletions": "Enable/disable showing completions on potentially undefined values that insert an optional chain call. Requires TS 3.7+ and strict null checks to be enabled.",
"configuration.suggest.includeCompletionsForImportStatements": "Enable/disable auto-import-style completions on partially-typed import statements. Requires using TypeScript 4.3+ in the workspace.",
"configuration.suggest.includeCompletionsWithSnippetText": "Enable/disable snippet completions from TS Server. Requires using TypeScript 4.3+ in the workspace.",
"typescript.tsdk.desc": "Specifies the folder path to the tsserver and lib*.d.ts files under a TypeScript install to use for IntelliSense, for example: `./node_modules/typescript/lib`.\n\n- When specified as a user setting, the TypeScript version from `typescript.tsdk` automatically replaces the built-in TypeScript version.\n- When specified as a workspace setting, `typescript.tsdk` allows you to switch to use that workspace version of TypeScript for IntelliSense with the `TypeScript: Select TypeScript version` command.\n\nSee the [TypeScript documentation](https://code.visualstudio.com/docs/typescript/typescript-compiling#_using-newer-typescript-versions) for more detail about managing TypeScript versions.",
"typescript.disableAutomaticTypeAcquisition": "Disables automatic type acquisition. Automatic type acquisition fetches `@types` packages from npm to improve IntelliSense for external libraries.",
"typescript.enablePromptUseWorkspaceTsdk": "Enables prompting of users to use the TypeScript version configured in the workspace for Intellisense.",

View file

@ -63,7 +63,7 @@ class MyCompletionItem extends vscode.CompletionItem {
) {
super(tsEntry.name, MyCompletionItem.convertKind(tsEntry.kind));
if (tsEntry.source) {
if (tsEntry.source && tsEntry.hasAction) {
// De-prioritze auto-imports
// https://github.com/microsoft/vscode/issues/40311
this.sortText = '\uffff' + tsEntry.sortText;
@ -78,16 +78,25 @@ class MyCompletionItem extends vscode.CompletionItem {
this.sortText = tsEntry.sortText;
}
// @ts-expect-error until 4.3 protocol update
if (tsEntry.sourceDisplay) {
// @ts-expect-error
this.label2 = { name: tsEntry.name, qualifier: Previewer.plain(tsEntry.sourceDisplay) };
}
this.preselect = tsEntry.isRecommended;
this.position = position;
this.useCodeSnippet = completionContext.useCodeSnippetsOnMethodSuggest && (this.kind === vscode.CompletionItemKind.Function || this.kind === vscode.CompletionItemKind.Method);
this.range = this.getRangeFromReplacementSpan(tsEntry, completionContext);
this.commitCharacters = MyCompletionItem.getCommitCharacters(completionContext, tsEntry);
this.insertText = tsEntry.insertText;
// @ts-expect-error until 4.3 protocol update
this.insertText = tsEntry.isSnippet && tsEntry.insertText
? new vscode.SnippetString(tsEntry.insertText)
: tsEntry.insertText;
this.filterText = this.getFilterText(completionContext.line, tsEntry.insertText);
if (completionContext.isMemberCompletion && completionContext.dotAccessorContext) {
if (completionContext.isMemberCompletion && completionContext.dotAccessorContext && !(this.insertText instanceof vscode.SnippetString)) {
this.filterText = completionContext.dotAccessorContext.text + (this.insertText || this.label);
if (!this.range) {
const replacementRange = this.getFuzzyWordRange();
@ -629,6 +638,7 @@ interface CompletionConfiguration {
readonly nameSuggestions: boolean;
readonly pathSuggestions: boolean;
readonly autoImportSuggestions: boolean;
readonly importStatementSuggestions: boolean;
}
namespace CompletionConfiguration {
@ -636,6 +646,7 @@ namespace CompletionConfiguration {
export const nameSuggestions = 'suggest.names';
export const pathSuggestions = 'suggest.paths';
export const autoImportSuggestions = 'suggest.autoImports';
export const importStatementSuggestions = 'suggest.importStatements';
export function getConfigurationForResource(
modeId: string,
@ -647,13 +658,14 @@ namespace CompletionConfiguration {
pathSuggestions: config.get<boolean>(CompletionConfiguration.pathSuggestions, true),
autoImportSuggestions: config.get<boolean>(CompletionConfiguration.autoImportSuggestions, true),
nameSuggestions: config.get<boolean>(CompletionConfiguration.nameSuggestions, true),
importStatementSuggestions: config.get<boolean>(CompletionConfiguration.nameSuggestions, true),
};
}
}
class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<MyCompletionItem> {
public static readonly triggerCharacters = ['.', '"', '\'', '`', '/', '@', '<', '#'];
public static readonly triggerCharacters = ['.', '"', '\'', '`', '/', '@', '<', '#', ' '];
constructor(
private readonly client: ITypeScriptServiceClient,
@ -695,7 +707,7 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
const line = document.lineAt(position.line);
const completionConfiguration = CompletionConfiguration.getConfigurationForResource(this.modeId, document.uri);
if (!this.shouldTrigger(context, line, position)) {
if (!this.shouldTrigger(context, line, position, completionConfiguration)) {
return undefined;
}
@ -740,7 +752,8 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
dotAccessorContext = { range, text };
}
}
isIncomplete = (response as any).metadata && (response as any).metadata.isIncomplete;
// @ts-expect-error until 4.3 protocol update
isIncomplete = !!response.body.isIncomplete || (response as any).metadata && (response as any).metadata.isIncomplete;
entries = response.body.entries;
metadata = response.metadata;
} else {
@ -821,6 +834,10 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
case '#': // Workaround for https://github.com/microsoft/TypeScript/issues/36367
return this.client.apiVersion.lt(API.v381) ? undefined : '#';
case ' ':
// @ts-expect-error until 4.3.0 protocol update
return this.client.apiVersion.gte(API.v430) ? ' ' : undefined;
case '.':
case '"':
case '\'':
@ -863,7 +880,8 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
private shouldTrigger(
context: vscode.CompletionContext,
line: vscode.TextLine,
position: vscode.Position
position: vscode.Position,
configuration: CompletionConfiguration,
): boolean {
if (context.triggerCharacter && this.client.apiVersion.lt(API.v290)) {
if ((context.triggerCharacter === '"' || context.triggerCharacter === '\'')) {
@ -894,7 +912,13 @@ class TypeScriptCompletionItemProvider implements vscode.CompletionItemProvider<
return false;
}
}
if (context.triggerCharacter === ' ') {
if (!configuration.importStatementSuggestions || this.client.apiVersion.lt(API.v430)) {
return false;
}
const pre = line.text.slice(0, position.character);
return pre === 'import';
}
return true;
}
}

View file

@ -183,6 +183,9 @@ export default class FileConfigurationManager extends Disposable {
includeAutomaticOptionalChainCompletions: config.get<boolean>('suggest.includeAutomaticOptionalChainCompletions', true),
provideRefactorNotApplicableReason: true,
generateReturnInDocTemplate: config.get<boolean>('suggest.jsdoc.generateReturns', true),
// @ts-expect-error until 4.3 protocol update
includeCompletionsForImportStatements: config.get<boolean>('suggest.includeCompletionsForImportStatements', true),
includeCompletionsWithSnippetText: config.get<boolean>('suggest.includeCompletionsWithSnippetText', true),
displayPartsForJSDoc: true,
};

View file

@ -35,6 +35,7 @@ export default class API {
public static readonly v400 = API.fromSimpleString('4.0.0');
public static readonly v401 = API.fromSimpleString('4.0.1');
public static readonly v420 = API.fromSimpleString('4.2.0');
public static readonly v430 = API.fromSimpleString('4.3.0');
public static fromVersionString(versionString: string): API {
let version = semver.valid(versionString);