Add the concept of client capabilities for TypeScript

For serverless, we will only be able to run the TypeScript syntax server which does not support all features. This change makes this possible by adding the concept of client capabilities. Providers such as rename will only be registered when the client has semantic capabilities
This commit is contained in:
Matt Bierner 2020-07-16 12:32:19 -07:00
parent 16c6b81b3e
commit 0857489caf
14 changed files with 99 additions and 35 deletions

View file

@ -3,23 +3,23 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as rimraf from 'rimraf';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { Api, getExtensionApi } from './api'; import { Api, getExtensionApi } from './api';
import { registerCommands } from './commands/index'; import { registerCommands } from './commands/index';
import { LanguageConfigurationManager } from './features/languageConfiguration'; import { LanguageConfigurationManager } from './features/languageConfiguration';
import * as task from './features/task';
import TypeScriptServiceClientHost from './typeScriptServiceClientHost'; import TypeScriptServiceClientHost from './typeScriptServiceClientHost';
import { flatten } from './utils/arrays'; import { flatten } from './utils/arrays';
import * as electron from './utils/electron';
import * as rimraf from 'rimraf';
import { CommandManager } from './utils/commandManager'; import { CommandManager } from './utils/commandManager';
import * as electron from './utils/electron';
import * as fileSchemes from './utils/fileSchemes'; import * as fileSchemes from './utils/fileSchemes';
import { standardLanguageDescriptions } from './utils/languageDescription'; import { standardLanguageDescriptions } from './utils/languageDescription';
import * as ProjectStatus from './utils/largeProjectStatus';
import { lazy, Lazy } from './utils/lazy'; import { lazy, Lazy } from './utils/lazy';
import LogDirectoryProvider from './utils/logDirectoryProvider'; import LogDirectoryProvider from './utils/logDirectoryProvider';
import ManagedFileContextManager from './utils/managedFileContext'; import ManagedFileContextManager from './utils/managedFileContext';
import { PluginManager } from './utils/plugins'; import { PluginManager } from './utils/plugins';
import * as ProjectStatus from './utils/largeProjectStatus';
import TscTaskProvider from './features/task';
export function activate( export function activate(
context: vscode.ExtensionContext context: vscode.ExtensionContext
@ -38,7 +38,7 @@ export function activate(
}); });
registerCommands(commandManager, lazyClientHost, pluginManager); registerCommands(commandManager, lazyClientHost, pluginManager);
context.subscriptions.push(vscode.tasks.registerTaskProvider('typescript', new TscTaskProvider(lazyClientHost.map(x => x.serviceClient)))); context.subscriptions.push(task.register(lazyClientHost.map(x => x.serviceClient)));
context.subscriptions.push(new LanguageConfigurationManager()); context.subscriptions.push(new LanguageConfigurationManager());
import('./features/tsconfig').then(module => { import('./features/tsconfig').then(module => {

View file

@ -5,7 +5,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService'; import { ITypeScriptServiceClient, ClientCapability } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { coalesce } from '../utils/arrays'; import { coalesce } from '../utils/arrays';
import { Delayer } from '../utils/async'; import { Delayer } from '../utils/async';
@ -302,9 +302,9 @@ class GetErrRequest {
onDone: () => void onDone: () => void
) { ) {
const allFiles = coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource))); const allFiles = coalesce(Array.from(files.entries).map(entry => client.normalizedPath(entry.resource)));
if (!allFiles.length) { if (!allFiles.length || !client.capabilities.has(ClientCapability.Semantic)) {
this._done = true; this._done = true;
onDone(); setImmediate(onDone);
} else { } else {
const request = client.configuration.enableProjectDiagnostics const request = client.configuration.enableProjectDiagnostics
// Note that geterrForProject is almost certainly not the api we want here as it ends up computing far // Note that geterrForProject is almost certainly not the api we want here as it ends up computing far

View file

@ -7,11 +7,11 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import * as PConst from '../protocol.const'; import * as PConst from '../protocol.const';
import { ITypeScriptServiceClient } from '../typescriptService';
import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration';
import { TypeScriptBaseCodeLensProvider, ReferencesCodeLens, getSymbolRange } from './baseCodeLensProvider';
import { CachedResponse } from '../tsServer/cachedResponse'; import { CachedResponse } from '../tsServer/cachedResponse';
import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService';
import { conditionalRegistration, requireCapability, requireConfiguration } from '../utils/dependentRegistration';
import * as typeConverters from '../utils/typeConverters'; import * as typeConverters from '../utils/typeConverters';
import { getSymbolRange, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@ -96,6 +96,7 @@ export function register(
) { ) {
return conditionalRegistration([ return conditionalRegistration([
requireConfiguration(modeId, 'implementationsCodeLens.enabled'), requireConfiguration(modeId, 'implementationsCodeLens.enabled'),
requireCapability(client, ClientCapability.Semantic),
], () => { ], () => {
return vscode.languages.registerCodeLensProvider(selector, return vscode.languages.registerCodeLensProvider(selector,
new TypeScriptImplementationsCodeLensProvider(client, cachedResponse)); new TypeScriptImplementationsCodeLensProvider(client, cachedResponse));

View file

@ -6,7 +6,7 @@
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService'; import { ITypeScriptServiceClient, ClientCapability } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { nulToken } from '../utils/cancellation'; import { nulToken } from '../utils/cancellation';
import { applyCodeActionCommands, getEditForCodeAction } from '../utils/codeAction'; import { applyCodeActionCommands, getEditForCodeAction } from '../utils/codeAction';
@ -18,6 +18,7 @@ import * as typeConverters from '../utils/typeConverters';
import { DiagnosticsManager } from './diagnostics'; import { DiagnosticsManager } from './diagnostics';
import FileConfigurationManager from './fileConfigurationManager'; import FileConfigurationManager from './fileConfigurationManager';
import { equals } from '../utils/objects'; import { equals } from '../utils/objects';
import { conditionalRegistration, requireCapability } from '../utils/dependentRegistration';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@ -409,7 +410,11 @@ export function register(
diagnosticsManager: DiagnosticsManager, diagnosticsManager: DiagnosticsManager,
telemetryReporter: TelemetryReporter telemetryReporter: TelemetryReporter
) { ) {
return vscode.languages.registerCodeActionsProvider(selector, return conditionalRegistration([
new TypeScriptQuickFixProvider(client, fileConfigurationManager, commandManager, diagnosticsManager, telemetryReporter), requireCapability(client, ClientCapability.Semantic),
TypeScriptQuickFixProvider.metadata); ], () => {
return vscode.languages.registerCodeActionsProvider(selector,
new TypeScriptQuickFixProvider(client, fileConfigurationManager, commandManager, diagnosticsManager, telemetryReporter),
TypeScriptQuickFixProvider.metadata);
});
} }

View file

@ -7,11 +7,11 @@ import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import { LearnMoreAboutRefactoringsCommand } from '../commands/learnMoreAboutRefactorings'; import { LearnMoreAboutRefactoringsCommand } from '../commands/learnMoreAboutRefactorings';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService'; import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { nulToken } from '../utils/cancellation'; import { nulToken } from '../utils/cancellation';
import { Command, CommandManager } from '../utils/commandManager'; import { Command, CommandManager } from '../utils/commandManager';
import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; import { conditionalRegistration, requireCapability, requireMinVersion } from '../utils/dependentRegistration';
import * as fileSchemes from '../utils/fileSchemes'; import * as fileSchemes from '../utils/fileSchemes';
import { TelemetryReporter } from '../utils/telemetry'; import { TelemetryReporter } from '../utils/telemetry';
import * as typeConverters from '../utils/typeConverters'; import * as typeConverters from '../utils/typeConverters';
@ -403,7 +403,8 @@ export function register(
telemetryReporter: TelemetryReporter, telemetryReporter: TelemetryReporter,
) { ) {
return conditionalRegistration([ return conditionalRegistration([
requireMinVersion(client, TypeScriptRefactorProvider.minVersion) requireMinVersion(client, TypeScriptRefactorProvider.minVersion),
requireCapability(client, ClientCapability.Semantic),
], () => { ], () => {
return vscode.languages.registerCodeActionsProvider(selector, return vscode.languages.registerCodeActionsProvider(selector,
new TypeScriptRefactorProvider(client, formattingOptionsManager, commandManager, telemetryReporter), new TypeScriptRefactorProvider(client, formattingOptionsManager, commandManager, telemetryReporter),

View file

@ -8,8 +8,8 @@ import * as nls from 'vscode-nls';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import * as PConst from '../protocol.const'; import * as PConst from '../protocol.const';
import { CachedResponse } from '../tsServer/cachedResponse'; import { CachedResponse } from '../tsServer/cachedResponse';
import { ITypeScriptServiceClient } from '../typescriptService'; import { ITypeScriptServiceClient, ClientCapability } from '../typescriptService';
import { conditionalRegistration, requireConfiguration } from '../utils/dependentRegistration'; import { conditionalRegistration, requireConfiguration, requireCapability } from '../utils/dependentRegistration';
import * as typeConverters from '../utils/typeConverters'; import * as typeConverters from '../utils/typeConverters';
import { getSymbolRange, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider'; import { getSymbolRange, ReferencesCodeLens, TypeScriptBaseCodeLensProvider } from './baseCodeLensProvider';
@ -128,7 +128,8 @@ export function register(
cachedResponse: CachedResponse<Proto.NavTreeResponse>, cachedResponse: CachedResponse<Proto.NavTreeResponse>,
) { ) {
return conditionalRegistration([ return conditionalRegistration([
requireConfiguration(modeId, 'referencesCodeLens.enabled') requireConfiguration(modeId, 'referencesCodeLens.enabled'),
requireCapability(client, ClientCapability.Semantic),
], () => { ], () => {
return vscode.languages.registerCodeLensProvider(selector, return vscode.languages.registerCodeLensProvider(selector,
new TypeScriptReferencesCodeLensProvider(client, cachedResponse, modeId)); new TypeScriptReferencesCodeLensProvider(client, cachedResponse, modeId));

View file

@ -7,8 +7,9 @@ import * as path from 'path';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import { ClientCapability, ITypeScriptServiceClient, ServerResponse } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { conditionalRegistration, requireCapability } from '../utils/dependentRegistration';
import * as typeConverters from '../utils/typeConverters'; import * as typeConverters from '../utils/typeConverters';
import FileConfigurationManager from './fileConfigurationManager'; import FileConfigurationManager from './fileConfigurationManager';
@ -141,6 +142,10 @@ export function register(
client: ITypeScriptServiceClient, client: ITypeScriptServiceClient,
fileConfigurationManager: FileConfigurationManager, fileConfigurationManager: FileConfigurationManager,
) { ) {
return vscode.languages.registerRenameProvider(selector, return conditionalRegistration([
new TypeScriptRenameProvider(client, fileConfigurationManager)); requireCapability(client, ClientCapability.Semantic),
], () => {
return vscode.languages.registerRenameProvider(selector,
new TypeScriptRenameProvider(client, fileConfigurationManager));
});
} }

View file

@ -7,9 +7,9 @@
import { TokenEncodingConsts, TokenModifier, TokenType, VersionRequirement } from 'typescript-vscode-sh-plugin/lib/constants'; import { TokenEncodingConsts, TokenModifier, TokenType, VersionRequirement } from 'typescript-vscode-sh-plugin/lib/constants';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as Proto from '../protocol'; import * as Proto from '../protocol';
import { ExecConfig, ITypeScriptServiceClient, ServerResponse } from '../typescriptService'; import { ClientCapability, ExecConfig, ITypeScriptServiceClient, ServerResponse } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; import { conditionalRegistration, requireCapability, requireMinVersion } from '../utils/dependentRegistration';
const minTypeScriptVersion = API.fromVersionString(`${VersionRequirement.major}.${VersionRequirement.minor}`); const minTypeScriptVersion = API.fromVersionString(`${VersionRequirement.major}.${VersionRequirement.minor}`);
@ -20,6 +20,7 @@ const CONTENT_LENGTH_LIMIT = 100000;
export function register(selector: vscode.DocumentSelector, client: ITypeScriptServiceClient) { export function register(selector: vscode.DocumentSelector, client: ITypeScriptServiceClient) {
return conditionalRegistration([ return conditionalRegistration([
requireMinVersion(client, minTypeScriptVersion), requireMinVersion(client, minTypeScriptVersion),
requireCapability(client, ClientCapability.Semantic),
], () => { ], () => {
const provider = new DocumentSemanticTokensProvider(client); const provider = new DocumentSemanticTokensProvider(client);
return vscode.Disposable.from( return vscode.Disposable.from(

View file

@ -35,7 +35,7 @@ interface TypeScriptTaskDefinition extends vscode.TaskDefinition {
/** /**
* Provides tasks for building `tsconfig.json` files in a project. * Provides tasks for building `tsconfig.json` files in a project.
*/ */
export default class TscTaskProvider implements vscode.TaskProvider { class TscTaskProvider implements vscode.TaskProvider {
private readonly projectInfoRequestTimeout = 2000; private readonly projectInfoRequestTimeout = 2000;
private autoDetect: AutoDetect = 'on'; private autoDetect: AutoDetect = 'on';
@ -291,3 +291,9 @@ export default class TscTaskProvider implements vscode.TaskProvider {
this.autoDetect = typeof type === 'undefined' ? 'on' : type; this.autoDetect = typeof type === 'undefined' ? 'on' : type;
} }
} }
export function register(
lazyClient: Lazy<ITypeScriptServiceClient>,
) {
return vscode.tasks.registerTaskProvider('typescript', new TscTaskProvider(lazyClient));
}

View file

@ -7,11 +7,11 @@ import * as path from 'path';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { ITypeScriptServiceClient } from '../typescriptService'; import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { Delayer } from '../utils/async'; import { Delayer } from '../utils/async';
import { nulToken } from '../utils/cancellation'; import { nulToken } from '../utils/cancellation';
import { conditionalRegistration, requireMinVersion } from '../utils/dependentRegistration'; import { conditionalRegistration, requireCapability, requireMinVersion } from '../utils/dependentRegistration';
import { Disposable } from '../utils/dispose'; import { Disposable } from '../utils/dispose';
import * as fileSchemes from '../utils/fileSchemes'; import * as fileSchemes from '../utils/fileSchemes';
import { doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription'; import { doesResourceLookLikeATypeScriptFile } from '../utils/languageDescription';
@ -296,6 +296,7 @@ export function register(
) { ) {
return conditionalRegistration([ return conditionalRegistration([
requireMinVersion(client, UpdateImportsOnFileRenameHandler.minVersion), requireMinVersion(client, UpdateImportsOnFileRenameHandler.minVersion),
requireCapability(client, ClientCapability.Semantic),
], () => { ], () => {
return new UpdateImportsOnFileRenameHandler(client, fileConfigurationManager, handles); return new UpdateImportsOnFileRenameHandler(client, fileConfigurationManager, handles);
}); });

View file

@ -8,6 +8,7 @@ import * as path from 'path';
import * as stream from 'stream'; import * as stream from 'stream';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import type * as Proto from '../protocol'; import type * as Proto from '../protocol';
import { ClientCapability } from '../typescriptService';
import API from '../utils/api'; import API from '../utils/api';
import { SeparateSyntaxServerConfiguration, TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; import { SeparateSyntaxServerConfiguration, TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration';
import * as electron from '../utils/electron'; import * as electron from '../utils/electron';
@ -36,6 +37,9 @@ const enum CompositeServerType {
/** Use a separate syntax server while the project is loading */ /** Use a separate syntax server while the project is loading */
DynamicSeparateSyntax, DynamicSeparateSyntax,
/** Only enable the syntax server */
SyntaxOnly
} }
export class TypeScriptServerSpawner { export class TypeScriptServerSpawner {
@ -50,12 +54,13 @@ export class TypeScriptServerSpawner {
public spawn( public spawn(
version: TypeScriptVersion, version: TypeScriptVersion,
capabilities: Set<ClientCapability>,
configuration: TypeScriptServiceConfiguration, configuration: TypeScriptServiceConfiguration,
pluginManager: PluginManager, pluginManager: PluginManager,
delegate: TsServerDelegate, delegate: TsServerDelegate,
): ITypeScriptServer { ): ITypeScriptServer {
let primaryServer: ITypeScriptServer; let primaryServer: ITypeScriptServer;
const serverType = this.getCompositeServerType(version, configuration); const serverType = this.getCompositeServerType(version, capabilities, configuration);
switch (serverType) { switch (serverType) {
case CompositeServerType.SeparateSyntax: case CompositeServerType.SeparateSyntax:
case CompositeServerType.DynamicSeparateSyntax: case CompositeServerType.DynamicSeparateSyntax:
@ -72,6 +77,11 @@ export class TypeScriptServerSpawner {
primaryServer = this.spawnTsServer(ServerKind.Main, version, configuration, pluginManager); primaryServer = this.spawnTsServer(ServerKind.Main, version, configuration, pluginManager);
break; break;
} }
case CompositeServerType.SyntaxOnly:
{
primaryServer = this.spawnTsServer(ServerKind.Syntax, version, configuration, pluginManager);
break;
}
} }
if (this.shouldUseSeparateDiagnosticsServer(configuration)) { if (this.shouldUseSeparateDiagnosticsServer(configuration)) {
@ -86,8 +96,13 @@ export class TypeScriptServerSpawner {
private getCompositeServerType( private getCompositeServerType(
version: TypeScriptVersion, version: TypeScriptVersion,
capabilities: Set<ClientCapability>,
configuration: TypeScriptServiceConfiguration, configuration: TypeScriptServiceConfiguration,
): CompositeServerType { ): CompositeServerType {
if (!capabilities.has(ClientCapability.Semantic)) {
return CompositeServerType.SyntaxOnly;
}
switch (configuration.separateSyntaxServer) { switch (configuration.separateSyntaxServer) {
case SeparateSyntaxServerConfiguration.Disabled: case SeparateSyntaxServerConfiguration.Disabled:
return CompositeServerType.Single; return CompositeServerType.Single;

View file

@ -85,6 +85,11 @@ export type ExecConfig = {
readonly cancelOnResourceChange?: vscode.Uri readonly cancelOnResourceChange?: vscode.Uri
}; };
export enum ClientCapability {
Syntax,
Semantic,
}
export interface ITypeScriptServiceClient { export interface ITypeScriptServiceClient {
/** /**
* Convert a resource (VS Code) to a normalized path (TypeScript). * Convert a resource (VS Code) to a normalized path (TypeScript).
@ -120,6 +125,9 @@ export interface ITypeScriptServiceClient {
readonly onDidEndInstallTypings: vscode.Event<Proto.EndInstallTypesEventBody>; readonly onDidEndInstallTypings: vscode.Event<Proto.EndInstallTypesEventBody>;
readonly onTypesInstallerInitializationFailed: vscode.Event<Proto.TypesInstallerInitializationFailedEventBody>; readonly onTypesInstallerInitializationFailed: vscode.Event<Proto.TypesInstallerInitializationFailedEventBody>;
readonly capabilities: Set<ClientCapability>;
readonly onDidChangeCapabilities: vscode.Event<Set<ClientCapability>>;
onReady(f: () => void): Promise<void>; onReady(f: () => void): Promise<void>;
showVersionPicker(): void; showVersionPicker(): void;

View file

@ -10,10 +10,11 @@ import * as nls from 'vscode-nls';
import BufferSyncSupport from './features/bufferSyncSupport'; import BufferSyncSupport from './features/bufferSyncSupport';
import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics'; import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics';
import * as Proto from './protocol'; import * as Proto from './protocol';
import { EventName } from './protocol.const';
import { ITypeScriptServer } from './tsServer/server'; import { ITypeScriptServer } from './tsServer/server';
import { TypeScriptServerError } from './tsServer/serverError'; import { TypeScriptServerError } from './tsServer/serverError';
import { TypeScriptServerSpawner } from './tsServer/spawner'; import { TypeScriptServerSpawner } from './tsServer/spawner';
import { ExecConfig, ITypeScriptServiceClient, ServerResponse, TypeScriptRequests } from './typescriptService'; import { ClientCapability, ExecConfig, ITypeScriptServiceClient, ServerResponse, TypeScriptRequests } from './typescriptService';
import API from './utils/api'; import API from './utils/api';
import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration';
import { Disposable } from './utils/dispose'; import { Disposable } from './utils/dispose';
@ -22,12 +23,11 @@ import LogDirectoryProvider from './utils/logDirectoryProvider';
import Logger from './utils/logger'; import Logger from './utils/logger';
import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider'; import { TypeScriptPluginPathsProvider } from './utils/pluginPathsProvider';
import { PluginManager } from './utils/plugins'; import { PluginManager } from './utils/plugins';
import { TelemetryReporter, VSCodeTelemetryReporter, TelemetryProperties } from './utils/telemetry'; import { TelemetryProperties, TelemetryReporter, VSCodeTelemetryReporter } from './utils/telemetry';
import Tracer from './utils/tracer'; import Tracer from './utils/tracer';
import { inferredProjectCompilerOptions, ProjectType } from './utils/tsconfig'; import { inferredProjectCompilerOptions, ProjectType } from './utils/tsconfig';
import { TypeScriptVersionManager } from './utils/versionManager'; import { TypeScriptVersionManager } from './utils/versionManager';
import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider'; import { TypeScriptVersion, TypeScriptVersionProvider } from './utils/versionProvider';
import { EventName } from './protocol.const';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@ -203,6 +203,16 @@ export default class TypeScriptServiceClient extends Disposable implements IType
})); }));
} }
public get capabilities() {
return new Set<ClientCapability>([
ClientCapability.Semantic,
ClientCapability.Syntax,
]);
}
private readonly _onDidChangeCapabilities = this._register(new vscode.EventEmitter<Set<ClientCapability>>());
readonly onDidChangeCapabilities = this._onDidChangeCapabilities.event;
private cancelInflightRequestsForResource(resource: vscode.Uri): void { private cancelInflightRequestsForResource(resource: vscode.Uri): void {
if (this.serverState.type !== ServerState.Type.Running) { if (this.serverState.type !== ServerState.Type.Running) {
return; return;
@ -337,7 +347,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType
const apiVersion = version.apiVersion || API.defaultVersion; const apiVersion = version.apiVersion || API.defaultVersion;
let mytoken = ++this.token; let mytoken = ++this.token;
const handle = this.typescriptServerSpawner.spawn(version, this.configuration, this.pluginManager, { const handle = this.typescriptServerSpawner.spawn(version, this.capabilities, this.configuration, this.pluginManager, {
onFatalError: (command, err) => this.fatalError(command, err), onFatalError: (command, err) => this.fatalError(command, err),
}); });
this.serverState = new ServerState.Running(handle, apiVersion, undefined, true); this.serverState = new ServerState.Running(handle, apiVersion, undefined, true);

View file

@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ITypeScriptServiceClient } from '../typescriptService'; import { ITypeScriptServiceClient, ClientCapability } from '../typescriptService';
import API from './api'; import API from './api';
import { Disposable } from './dispose'; import { Disposable } from './dispose';
@ -95,3 +95,13 @@ export function requireConfiguration(
vscode.workspace.onDidChangeConfiguration vscode.workspace.onDidChangeConfiguration
); );
} }
export function requireCapability(
client: ITypeScriptServiceClient,
requiredCapability: ClientCapability,
) {
return new Condition(
() => client.capabilities.has(requiredCapability),
client.onDidChangeCapabilities
);
}