diff --git a/extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts b/extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts index 63bf9f70638..e395806306e 100644 --- a/extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts +++ b/extensions/typescript-language-features/src/features/directiveCommentCompletionProvider.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import * as nls from 'vscode-nls'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { VersionDependentRegistration } from '../utils/versionDependentRegistration'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; const localize = nls.loadMessageBundle(); diff --git a/extensions/typescript-language-features/src/features/foldingProvider.ts b/extensions/typescript-language-features/src/features/foldingProvider.ts index d098651f5a6..c48ed6a877b 100644 --- a/extensions/typescript-language-features/src/features/foldingProvider.ts +++ b/extensions/typescript-language-features/src/features/foldingProvider.ts @@ -7,7 +7,7 @@ import * as vscode from 'vscode'; import * as Proto from '../protocol'; import { ITypeScriptServiceClient } from '../typescriptService'; import * as typeConverters from '../utils/typeConverters'; -import { VersionDependentRegistration } from '../utils/versionDependentRegistration'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; class TypeScriptFoldingProvider implements vscode.FoldingRangeProvider { public constructor( diff --git a/extensions/typescript-language-features/src/features/implementationProvider.ts b/extensions/typescript-language-features/src/features/implementationProvider.ts index 055023c65e8..4615b72908a 100644 --- a/extensions/typescript-language-features/src/features/implementationProvider.ts +++ b/extensions/typescript-language-features/src/features/implementationProvider.ts @@ -6,7 +6,7 @@ import * as vscode from 'vscode'; import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; -import { VersionDependentRegistration } from '../utils/versionDependentRegistration'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; import DefinitionProviderBase from './definitionProviderBase'; class TypeScriptImplementationProvider extends DefinitionProviderBase implements vscode.ImplementationProvider { diff --git a/extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts b/extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts index fdd5e7ceacc..be1f992af49 100644 --- a/extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts +++ b/extensions/typescript-language-features/src/features/implementationsCodeLensProvider.ts @@ -3,39 +3,38 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeLens, CancellationToken, TextDocument, Range, Location, workspace } from 'vscode'; +import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; - -import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, CachedNavTreeResponse } from './baseCodeLensProvider'; import { ITypeScriptServiceClient } from '../typescriptService'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; import * as typeConverters from '../utils/typeConverters'; - -import * as nls from 'vscode-nls'; +import { CachedNavTreeResponse, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'; +import { disposeAll } from '../utils/dispose'; const localize = nls.loadMessageBundle(); export default class TypeScriptImplementationsCodeLensProvider extends TypeScriptBaseCodeLensProvider { + + private readonly _disposables: vscode.Disposable[] = []; + public constructor( client: ITypeScriptServiceClient, private readonly language: string, cachedResponse: CachedNavTreeResponse ) { super(client, cachedResponse); + + this.updateConfiguration(); + + vscode.workspace.onDidChangeConfiguration(() => this.updateConfiguration(), null, this._disposables); } - public updateConfiguration(): void { - const config = workspace.getConfiguration(this.language); - this.setEnabled(config.get('implementationsCodeLens.enabled', false)); + public dispose() { + disposeAll(this._disposables); } - public async provideCodeLenses(document: TextDocument, token: CancellationToken): Promise { - if (!this.client.apiVersion.has220Features()) { - return []; - } - return super.provideCodeLenses(document, token); - } - - public resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { + public resolveCodeLens(inputCodeLens: vscode.CodeLens, token: vscode.CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); return this.client.execute('implementation', args, token).then(response => { @@ -46,10 +45,10 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip const locations = response.body .map(reference => // Only take first line on implementation: https://github.com/Microsoft/vscode/issues/23924 - new Location(this.client.asUrl(reference.file), + new vscode.Location(this.client.asUrl(reference.file), reference.start.line === reference.end.line ? typeConverters.Range.fromTextSpan(reference) - : new Range( + : new vscode.Range( reference.start.line - 1, reference.start.offset - 1, reference.start.line, 0))) // Exclude original from implementations @@ -76,10 +75,10 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip } protected extractSymbol( - document: TextDocument, + document: vscode.TextDocument, item: Proto.NavigationTree, _parent: Proto.NavigationTree | null - ): Range | null { + ): vscode.Range | null { switch (item.kind) { case PConst.Kind.interface: return super.getSymbolRange(document, item); @@ -96,4 +95,30 @@ export default class TypeScriptImplementationsCodeLensProvider extends TypeScrip } return null; } + + private updateConfiguration(): void { + const config = vscode.workspace.getConfiguration(this.language); + this.setEnabled(config.get('implementationsCodeLens.enabled', false)); + } +} + + +export function register( + selector: vscode.DocumentSelector, + modeId: string, + client: ITypeScriptServiceClient, + cachedResponse: CachedNavTreeResponse, +) { + return new VersionDependentRegistration(client, { + isSupportedVersion(api) { + return api.has220Features(); + }, + register() { + const provider = new TypeScriptImplementationsCodeLensProvider(client, modeId, cachedResponse); + return vscode.Disposable.from( + vscode.languages.registerCodeLensProvider(selector, provider), + provider, + ); + } + }); } diff --git a/extensions/typescript-language-features/src/features/organizeImports.ts b/extensions/typescript-language-features/src/features/organizeImports.ts index 1da5b9823fa..a4ba43b9799 100644 --- a/extensions/typescript-language-features/src/features/organizeImports.ts +++ b/extensions/typescript-language-features/src/features/organizeImports.ts @@ -10,7 +10,7 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import { Command, CommandManager } from '../utils/commandManager'; import * as typeconverts from '../utils/typeConverters'; import FileConfigurationManager from './fileConfigurationManager'; -import { VersionDependentRegistration } from '../utils/versionDependentRegistration'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; const localize = nls.loadMessageBundle(); diff --git a/extensions/typescript-language-features/src/features/refactorProvider.ts b/extensions/typescript-language-features/src/features/refactorProvider.ts index 7c53b399779..ecc2fbb02dd 100644 --- a/extensions/typescript-language-features/src/features/refactorProvider.ts +++ b/extensions/typescript-language-features/src/features/refactorProvider.ts @@ -11,7 +11,7 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import * as typeConverters from '../utils/typeConverters'; import FormattingOptionsManager from './fileConfigurationManager'; import { CommandManager, Command } from '../utils/commandManager'; -import { VersionDependentRegistration } from '../utils/versionDependentRegistration'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; class ApplyRefactoringCommand implements Command { public static readonly ID = '_typescript.applyRefactoring'; diff --git a/extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts b/extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts index fdff948985d..da55dff2a0e 100644 --- a/extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts +++ b/extensions/typescript-language-features/src/features/referencesCodeLensProvider.ts @@ -3,39 +3,37 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { CodeLens, CancellationToken, TextDocument, Range, workspace } from 'vscode'; +import * as vscode from 'vscode'; +import * as nls from 'vscode-nls'; import * as Proto from '../protocol'; import * as PConst from '../protocol.const'; - -import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, CachedNavTreeResponse } from './baseCodeLensProvider'; import { ITypeScriptServiceClient } from '../typescriptService'; import * as typeConverters from '../utils/typeConverters'; +import { CachedNavTreeResponse, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'; +import { disposeAll } from '../utils/dispose'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; -import * as nls from 'vscode-nls'; const localize = nls.loadMessageBundle(); -export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider { +class TypeScriptReferencesCodeLensProvider extends TypeScriptBaseCodeLensProvider { + private readonly _disposables: vscode.Disposable[] = []; + public constructor( client: ITypeScriptServiceClient, private readonly language: string, cachedResponse: CachedNavTreeResponse ) { super(client, cachedResponse); + + this.updateConfiguration(); + vscode.workspace.onDidChangeConfiguration(() => this.updateConfiguration(), null, this._disposables); } - public updateConfiguration(): void { - const config = workspace.getConfiguration(this.language); - this.setEnabled(config.get('referencesCodeLens.enabled', false)); + public dispose() { + disposeAll(this._disposables); } - async provideCodeLenses(document: TextDocument, token: CancellationToken): Promise { - if (!this.client.apiVersion.has206Features()) { - return []; - } - return super.provideCodeLenses(document, token); - } - - public resolveCodeLens(inputCodeLens: CodeLens, token: CancellationToken): Promise { + public resolveCodeLens(inputCodeLens: vscode.CodeLens, token: vscode.CancellationToken): Promise { const codeLens = inputCodeLens as ReferencesCodeLens; const args = typeConverters.Position.toFileLocationRequestArgs(codeLens.file, codeLens.range.start); return this.client.execute('references', args, token).then(response => { @@ -69,10 +67,10 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase } protected extractSymbol( - document: TextDocument, + document: vscode.TextDocument, item: Proto.NavigationTree, parent: Proto.NavigationTree | null - ): Range | null { + ): vscode.Range | null { if (parent && parent.kind === PConst.Kind.enum) { return super.getSymbolRange(document, item); } @@ -107,4 +105,29 @@ export default class TypeScriptReferencesCodeLensProvider extends TypeScriptBase return null; } + + private updateConfiguration(): void { + const config = vscode.workspace.getConfiguration(this.language); + this.setEnabled(config.get('referencesCodeLens.enabled', false)); + } } + +export function register( + selector: vscode.DocumentSelector, + modeId: string, + client: ITypeScriptServiceClient, + cachedResponse: CachedNavTreeResponse, +) { + return new VersionDependentRegistration(client, { + isSupportedVersion(api) { + return api.has206Features(); + }, + register() { + const referenceCodeLensProvider = new TypeScriptReferencesCodeLensProvider(client, modeId, cachedResponse); + return vscode.Disposable.from( + vscode.languages.registerCodeLensProvider(selector, referenceCodeLensProvider), + referenceCodeLensProvider, + ); + } + }); +} \ No newline at end of file diff --git a/extensions/typescript-language-features/src/features/typeDefinitionProvider.ts b/extensions/typescript-language-features/src/features/typeDefinitionProvider.ts index f6d44e1026c..8b0fb1ea34b 100644 --- a/extensions/typescript-language-features/src/features/typeDefinitionProvider.ts +++ b/extensions/typescript-language-features/src/features/typeDefinitionProvider.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import { ITypeScriptServiceClient } from '../typescriptService'; -import { VersionDependentRegistration } from '../utils/versionDependentRegistration'; +import { VersionDependentRegistration } from '../utils/dependentRegistration'; import DefinitionProviderBase from './definitionProviderBase'; import API from '../utils/api'; diff --git a/extensions/typescript-language-features/src/languageProvider.ts b/extensions/typescript-language-features/src/languageProvider.ts index 96fbbbe58d7..2816566d8c4 100644 --- a/extensions/typescript-language-features/src/languageProvider.ts +++ b/extensions/typescript-language-features/src/languageProvider.ts @@ -30,8 +30,6 @@ export default class LanguageProvider { private readonly bufferSyncSupport: BufferSyncSupport; private readonly fileConfigurationManager: FileConfigurationManager; - private readonly toUpdateOnConfigurationChanged: ({ updateConfiguration: () => void })[] = []; - private _validate: boolean = true; private _enableSuggestionDiagnostics: boolean = true; @@ -111,25 +109,17 @@ export default class LanguageProvider { this.disposables.push((await import('./features/formattingProvider')).register(selector, this.description.id, config, client, this.fileConfigurationManager)); this.disposables.push((await import('./features/hoverProvider')).register(selector, client)); this.disposables.push((await import('./features/implementationProvider')).register(selector, client)); + this.disposables.push((await import('./features/implementationsCodeLensProvider')).register(selector, this.description.id, client, cachedResponse)); this.disposables.push((await import('./features/jsDocCompletionProvider')).register(selector, client, commandManager)); this.disposables.push((await import('./features/organizeImports')).register(selector, client, this.commandManager, this.fileConfigurationManager)); this.disposables.push((await import('./features/quickFixProvider')).register(selector, client, this.fileConfigurationManager, commandManager, this.diagnosticsManager, this.bufferSyncSupport, this.telemetryReporter)); this.disposables.push((await import('./features/refactorProvider')).register(selector, client, this.fileConfigurationManager, commandManager)); this.disposables.push((await import('./features/referenceProvider')).register(selector, client)); + this.disposables.push((await import('./features/referencesCodeLensProvider')).register(selector, this.description.id, client, cachedResponse)); this.disposables.push((await import('./features/renameProvider')).register(selector, client)); this.disposables.push((await import('./features/signatureHelpProvider')).register(selector, client)); this.disposables.push((await import('./features/typeDefinitionProvider')).register(selector, client)); - const referenceCodeLensProvider = new (await import('./features/referencesCodeLensProvider')).default(client, this.description.id, cachedResponse); - referenceCodeLensProvider.updateConfiguration(); - this.toUpdateOnConfigurationChanged.push(referenceCodeLensProvider); - this.disposables.push(vscode.languages.registerCodeLensProvider(selector, referenceCodeLensProvider)); - - const implementationCodeLensProvider = new (await import('./features/implementationsCodeLensProvider')).default(client, this.description.id, cachedResponse); - implementationCodeLensProvider.updateConfiguration(); - this.toUpdateOnConfigurationChanged.push(implementationCodeLensProvider); - this.disposables.push(vscode.languages.registerCodeLensProvider(selector, implementationCodeLensProvider)); - this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new (await import('./features/workspaceSymbolProvider')).default(client, this.description.modeIds))); } @@ -137,10 +127,6 @@ export default class LanguageProvider { const config = vscode.workspace.getConfiguration(this.id, null); this.updateValidate(config.get(validateSetting, true)); this.updateSuggestionDiagnostics(config.get(suggestionSetting, true)); - - for (const toUpdate of this.toUpdateOnConfigurationChanged) { - toUpdate.updateConfiguration(); - } } public handles(resource: vscode.Uri, doc: vscode.TextDocument): boolean { diff --git a/extensions/typescript-language-features/src/utils/versionDependentRegistration.ts b/extensions/typescript-language-features/src/utils/dependentRegistration.ts similarity index 68% rename from extensions/typescript-language-features/src/utils/versionDependentRegistration.ts rename to extensions/typescript-language-features/src/utils/dependentRegistration.ts index 79b5d153d45..0011bb856b3 100644 --- a/extensions/typescript-language-features/src/utils/versionDependentRegistration.ts +++ b/extensions/typescript-language-features/src/utils/dependentRegistration.ts @@ -8,39 +8,24 @@ import { ITypeScriptServiceClient } from '../typescriptService'; import API from '../utils/api'; import { disposeAll } from '../utils/dispose'; -export interface Delegate { - isSupportedVersion(api: API): boolean; - register(): vscode.Disposable; -} - -export class VersionDependentRegistration { +class ConditionalRegistration { private registration: vscode.Disposable | undefined = undefined; - private readonly _disposables: vscode.Disposable[] = []; - - constructor( - private readonly client: ITypeScriptServiceClient, - private readonly delegate: Delegate, - ) { - this.update(client.apiVersion); - - this.client.onTsServerStarted(() => { - this.update(this.client.apiVersion); - }, null, this._disposables); - } + public constructor( + private readonly _doRegister: () => vscode.Disposable + ) { } public dispose() { - disposeAll(this._disposables); if (this.registration) { this.registration.dispose(); this.registration = undefined; } } - private update(api: API) { - if (this.delegate.isSupportedVersion(api)) { + public update(enabled: boolean) { + if (enabled) { if (!this.registration) { - this.registration = this.delegate.register(); + this.registration = this._doRegister(); } } else { if (this.registration) { @@ -50,3 +35,36 @@ export class VersionDependentRegistration { } } } + +export interface VersionDependentRegistrationDelegate { + isSupportedVersion(api: API): boolean; + register(): vscode.Disposable; +} + +export class VersionDependentRegistration { + private readonly _registration: ConditionalRegistration; + + private readonly _disposables: vscode.Disposable[] = []; + + constructor( + private readonly client: ITypeScriptServiceClient, + private readonly delegate: VersionDependentRegistrationDelegate, + ) { + this._registration = new ConditionalRegistration(this.delegate.register); + + this.update(client.apiVersion); + + this.client.onTsServerStarted(() => { + this.update(this.client.apiVersion); + }, null, this._disposables); + } + + public dispose() { + disposeAll(this._disposables); + this._registration.dispose(); + } + + private update(api: API) { + this._registration.update(this.delegate.isSupportedVersion(api)); + } +}