diff --git a/extensions/typescript-language-features/package.json b/extensions/typescript-language-features/package.json index 5ee66760548..78201193e17 100644 --- a/extensions/typescript-language-features/package.json +++ b/extensions/typescript-language-features/package.json @@ -602,6 +602,18 @@ "description": "%configuration.suggest.completeJSDocs%", "scope": "resource" }, + "javascript.suggest.jsdoc.generateReturns": { + "type": "boolean", + "default": true, + "markdownDescription": "%configuration.suggest.jsdoc.generateReturns%", + "scope": "resource" + }, + "typescript.suggest.jsdoc.generateReturns": { + "type": "boolean", + "default": true, + "markdownDescription": "%configuration.suggest.jsdoc.generateReturns%", + "scope": "resource" + }, "typescript.locale": { "type": [ "string", diff --git a/extensions/typescript-language-features/package.nls.json b/extensions/typescript-language-features/package.nls.json index b6407a50b37..85f9a75b507 100644 --- a/extensions/typescript-language-features/package.nls.json +++ b/extensions/typescript-language-features/package.nls.json @@ -68,6 +68,7 @@ "configuration.javascript.checkJs.experimentalDecorators.deprecation": "This setting has been deprecated in favor of `js/ts.implicitProjectConfig.experimentalDecorators`.", "configuration.implicitProjectConfig.strictNullChecks": "Enable/disable [strict null checks](https://www.typescriptlang.org/tsconfig#strictNullChecks) in JavaScript and TypeScript files that are not part of a project. Existing `jsconfig.json` or `tsconfig.json` files override this setting.", "configuration.implicitProjectConfig.strictFunctionTypes": "Enable/disable [strict function types](https://www.typescriptlang.org/tsconfig#strictFunctionTypes) in JavaScript and TypeScript files that are not part of a project. Existing `jsconfig.json` or `tsconfig.json` files override this setting.", + "configuration.suggest.jsdoc.generateReturns": "Enable/disable generating `@return` annotations for JSDoc templates. Requires using TypeScript 4.2+ in the workspace.", "configuration.suggest.autoImports": "Enable/disable auto import suggestions.", "taskDefinition.tsconfig.description": "The tsconfig file that defines the TS build.", "javascript.suggestionActions.enabled": "Enable/disable suggestion diagnostics for JavaScript files in the editor.", diff --git a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts index b45ad7ee380..f0c41541b76 100644 --- a/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts +++ b/extensions/typescript-language-features/src/languageFeatures/fileConfigurationManager.ts @@ -182,6 +182,7 @@ export default class FileConfigurationManager extends Disposable { allowRenameOfImportPath: true, includeAutomaticOptionalChainCompletions: config.get('suggest.includeAutomaticOptionalChainCompletions', true), provideRefactorNotApplicableReason: true, + generateReturnInDocTemplate: config.get('suggest.jsdoc.generateReturns', true), }; return preferences; diff --git a/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts b/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts index 6efe472e4f9..67548f5ec19 100644 --- a/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts +++ b/extensions/typescript-language-features/src/languageFeatures/jsDocCompletions.ts @@ -9,6 +9,7 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration'; import { DocumentSelector } from '../utils/documentSelector'; import * as typeConverters from '../utils/typeConverters'; +import FileConfigurationManager from './fileConfigurationManager'; const localize = nls.loadMessageBundle(); @@ -37,6 +38,7 @@ class JsDocCompletionProvider implements vscode.CompletionItemProvider { constructor( private readonly client: ITypeScriptServiceClient, + private readonly fileConfigurationManager: FileConfigurationManager, ) { } public async provideCompletionItems( @@ -53,8 +55,12 @@ class JsDocCompletionProvider implements vscode.CompletionItemProvider { return undefined; } - const args = typeConverters.Position.toFileLocationRequestArgs(file, position); - const response = await this.client.execute('docCommentTemplate', args, token); + const response = await this.client.interruptGetErr(async () => { + await this.fileConfigurationManager.ensureConfigurationForDocument(document, token); + + const args = typeConverters.Position.toFileLocationRequestArgs(file, position); + return this.client.execute('docCommentTemplate', args, token); + }); if (response.type !== 'response' || !response.body) { return undefined; } @@ -107,6 +113,9 @@ export function templateToSnippet(template: string): vscode.SnippetString { out += post + ` \${${snippetIndex++}}`; return out; }); + + template = template.replace(/\* @returns[ \t]*$/gm, `* @returns \${${snippetIndex++}}`); + return new vscode.SnippetString(template); } @@ -114,12 +123,14 @@ export function register( selector: DocumentSelector, modeId: string, client: ITypeScriptServiceClient, + fileConfigurationManager: FileConfigurationManager, + ): vscode.Disposable { return conditionalRegistration([ requireConfiguration(modeId, 'suggest.completeJSDocs') ], () => { return vscode.languages.registerCompletionItemProvider(selector.syntax, - new JsDocCompletionProvider(client), + new JsDocCompletionProvider(client, fileConfigurationManager), '*'); }); } diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index 5634edb44df..2cb36eb948b 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -72,7 +72,7 @@ export default class LanguageProvider extends Disposable { import('./languageFeatures/formatting').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.fileConfigurationManager))), import('./languageFeatures/hover').then(provider => this._register(provider.register(selector, this.client))), import('./languageFeatures/implementations').then(provider => this._register(provider.register(selector, this.client))), - import('./languageFeatures/jsDocCompletions').then(provider => this._register(provider.register(selector, this.description.id, this.client))), + import('./languageFeatures/jsDocCompletions').then(provider => this._register(provider.register(selector, this.description.id, this.client, this.fileConfigurationManager))), import('./languageFeatures/organizeImports').then(provider => this._register(provider.register(selector, this.client, this.commandManager, this.fileConfigurationManager, this.telemetryReporter))), import('./languageFeatures/quickFix').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.client.diagnosticsManager, this.telemetryReporter))), import('./languageFeatures/refactor').then(provider => this._register(provider.register(selector, this.client, this.fileConfigurationManager, this.commandManager, this.telemetryReporter))),