diff --git a/extensions/typescript-language-features/src/tsServer/server.ts b/extensions/typescript-language-features/src/tsServer/server.ts index db7810ad96fb44298a1e3cd987d75e4c5315c7c1..f607027429335b27abd03509932d939b2a0fb6ec 100644 --- a/extensions/typescript-language-features/src/tsServer/server.ts +++ b/extensions/typescript-language-features/src/tsServer/server.ts @@ -8,7 +8,7 @@ import * as fs from 'fs'; import * as path from 'path'; import * as vscode from 'vscode'; import * as Proto from '../protocol'; -import { CancelledResponse, NoContentResponse } from '../typescriptService'; +import { CancelledResponse, NoContentResponse, ServerResponse } from '../typescriptService'; import API from '../utils/api'; import { TsServerLogLevel, TypeScriptServiceConfiguration } from '../utils/configuration'; import { Disposable } from '../utils/dispose'; @@ -307,7 +307,9 @@ export class TypeScriptServer extends Disposable { } } - public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise { + public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + public executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { const request = this._requestQueue.createRequest(command, args); const requestInfo: RequestItem = { request, @@ -315,9 +317,9 @@ export class TypeScriptServer extends Disposable { isAsync: executeInfo.isAsync, queueingType: getQueueingType(command, executeInfo.lowPriority) }; - let result: Promise; + let result: Promise> | undefined; if (executeInfo.expectsResult) { - result = new Promise((resolve, reject) => { + result = new Promise>((resolve, reject) => { this._callbacks.add(request.seq, { onSuccess: resolve, onError: reject, startTime: Date.now(), isAsync: executeInfo.isAsync }, executeInfo.isAsync); if (executeInfo.token) { @@ -346,9 +348,8 @@ export class TypeScriptServer extends Disposable { throw err; }); - } else { - result = Promise.resolve(null); } + this._requestQueue.enqueue(requestInfo); this.sendNextRequests(); diff --git a/extensions/typescript-language-features/src/typescriptService.ts b/extensions/typescript-language-features/src/typescriptService.ts index db791db8fc1e06ef074775d9b95582b6b504e541..eb48a67b99a686755a85a582b4b98034fb79bc12 100644 --- a/extensions/typescript-language-features/src/typescriptService.ts +++ b/extensions/typescript-language-features/src/typescriptService.ts @@ -20,10 +20,11 @@ export class CancelledResponse { } export const NoContentResponse = new class { readonly type = 'noContent'; }; +export const LanguageServiceDisabledContentResponse = new class { readonly type = 'languageServiceDisabled'; }; -export type ServerResponse = T | CancelledResponse | typeof NoContentResponse; +export type ServerResponse = T | CancelledResponse | typeof NoContentResponse | typeof LanguageServiceDisabledContentResponse; -interface TypeScriptRequestTypes { +export interface TypeScriptRequestTypes { 'applyCodeActionCommand': [Proto.ApplyCodeActionCommandRequestArgs, Proto.ApplyCodeActionCommandResponse]; 'completionEntryDetails': [Proto.CompletionDetailsRequestArgs, Proto.CompletionDetailsResponse]; 'completionInfo': [Proto.CompletionsRequestArgs, Proto.CompletionInfoResponse]; @@ -110,7 +111,7 @@ export interface ITypeScriptServiceClient { executeWithoutWaitingForResponse(command: 'compilerOptionsForInferredProjects', args: Proto.SetCompilerOptionsForInferredProjectsArgs): void; executeWithoutWaitingForResponse(command: 'reloadProjects', args: null): void; - executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise; + executeAsync(command: 'geterr', args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise>; /** * Cancel on going geterr requests and re-queue them after `f` has been evaluated. diff --git a/extensions/typescript-language-features/src/typescriptServiceClient.ts b/extensions/typescript-language-features/src/typescriptServiceClient.ts index 864d028f6fe4c80bb408691f7a40a21a50c86dd7..bc0a58ac97c41a486261f6966e363f4a933545ed 100644 --- a/extensions/typescript-language-features/src/typescriptServiceClient.ts +++ b/extensions/typescript-language-features/src/typescriptServiceClient.ts @@ -11,7 +11,7 @@ import BufferSyncSupport from './features/bufferSyncSupport'; import { DiagnosticKind, DiagnosticsManager } from './features/diagnostics'; import * as Proto from './protocol'; import { TypeScriptServer, TypeScriptServerSpawner } from './tsServer/server'; -import { ITypeScriptServiceClient } from './typescriptService'; +import { ITypeScriptServiceClient, ServerResponse, LanguageServiceDisabledContentResponse } from './typescriptService'; import API from './utils/api'; import { TsServerLogLevel, TypeScriptServiceConfiguration } from './utils/configuration'; import { Disposable } from './utils/dispose'; @@ -57,6 +57,7 @@ namespace ServerState { * Version reported by currently-running tsserver. */ public tsserverVersion: string | undefined, + public langaugeServiceEnabled: boolean, ) { } } @@ -243,16 +244,16 @@ export default class TypeScriptServiceClient extends Disposable implements IType this.telemetryReporter.logTelemetry(eventName, properties); } - private service(): TypeScriptServer { + private service(): ServerState.Running { if (this.serverState.type === ServerState.Type.Running) { - return this.serverState.server; + return this.serverState; } if (this.serverState.type === ServerState.Type.Errored) { throw this.serverState.error; } const newState = this.startService(); if (newState.type === ServerState.Type.Running) { - return newState.server; + return newState; } throw new Error('Could not create TS service'); } @@ -285,7 +286,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType let mytoken = ++this.token; const handle = this.typescriptServerSpawner.spawn(currentVersion, this.configuration, this.pluginManager); - this.serverState = new ServerState.Running(handle, apiVersion, undefined); + this.serverState = new ServerState.Running(handle, apiVersion, undefined, true); this.lastStart = Date.now(); handle.onError((err: Error) => { @@ -589,7 +590,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType return undefined; } - public execute(command: string, args: any, token: vscode.CancellationToken, lowPriority?: boolean): Promise { + public execute(command: string, args: any, token: vscode.CancellationToken, lowPriority?: boolean): Promise> { return this.executeImpl(command, args, { isAsync: false, token, @@ -606,7 +607,7 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - public executeAsync(command: string, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise { + public executeAsync(command: string, args: Proto.GeterrRequestArgs, token: vscode.CancellationToken): Promise> { return this.executeImpl(command, args, { isAsync: true, token, @@ -614,12 +615,30 @@ export default class TypeScriptServiceClient extends Disposable implements IType }); } - private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise { - const server = this.service(); - if (!server) { - return Promise.reject(new Error('Could not load TS Server')); + private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: false, lowPriority?: boolean }): undefined; + private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise>; + private executeImpl(command: string, args: any, executeInfo: { isAsync: boolean, token?: vscode.CancellationToken, expectsResult: boolean, lowPriority?: boolean }): Promise> | undefined { + const runningServerState = this.service(); + + if (!runningServerState.langaugeServiceEnabled) { + const nonSemanticCommands: string[] = [ + 'change', + 'close', + 'compilerOptionsForInferredProjects', + 'configure', + 'format', + 'formatonkey', + 'getOutliningSpans', + 'open', + 'projectInfo', + 'reloadProjects', + ]; + if (nonSemanticCommands.indexOf(command) === -1) { + return Promise.resolve(LanguageServiceDisabledContentResponse); + } } - return server.executeImpl(command, args, executeInfo); + + return runningServerState.server.executeImpl(command, args, executeInfo); } public interuptGetErr(f: () => R): R { @@ -649,14 +668,23 @@ export default class TypeScriptServiceClient extends Disposable implements IType break; case 'telemetry': - const telemetryData = (event as Proto.TelemetryEvent).body; - this.dispatchTelemetryEvent(telemetryData); - break; - + { + const body = (event as Proto.TelemetryEvent).body; + this.dispatchTelemetryEvent(body); + break; + } case 'projectLanguageServiceState': - this._onProjectLanguageServiceStateChanged.fire((event as Proto.ProjectLanguageServiceStateEvent).body); - break; - + { + const body = (event as Proto.ProjectLanguageServiceStateEvent).body!; + if (this.serverState.type === ServerState.Type.Running) { + this.serverState = { + ...this.serverState, + langaugeServiceEnabled: body.languageServiceEnabled, + }; + } + this._onProjectLanguageServiceStateChanged.fire(body); + break; + } case 'projectsUpdatedInBackground': const body = (event as Proto.ProjectsUpdatedInBackgroundEvent).body; const resources = body.openFiles.map(vscode.Uri.file); @@ -721,7 +749,10 @@ export default class TypeScriptServiceClient extends Disposable implements IType } if (telemetryData.telemetryEventName === 'projectInfo') { if (this.serverState.type === ServerState.Type.Running) { - this.serverState = new ServerState.Running(this.serverState.server, this.serverState.apiVersion, properties['version']); + this.serverState = { + ...this.serverState, + tsserverVersion: properties['version'] + }; } } diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index aa08a4c20db6f1e4e036af9e311e4f27bc8d3774..ff79983d255b68b6b89adffd67d085ed12066557 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -206,7 +206,7 @@ export class CodeActionModel { } if (this._state.type === CodeActionsState.Type.Triggered) { - this._state.actions.cancel(); + // this._state.actions.cancel(); } this.setState(CodeActionsState.Empty);