diff --git a/extensions/typescript/src/typescriptMain.ts b/extensions/typescript/src/typescriptMain.ts index 7bc9120c593..f633472ab55 100644 --- a/extensions/typescript/src/typescriptMain.ts +++ b/extensions/typescript/src/typescriptMain.ts @@ -443,6 +443,15 @@ class TypeScriptServiceClientHost implements ITypescriptServiceClientHost { return this.client; } + public restartTsServer(): void { + this.client.restartTsServer(); + if (this.languages) { + for (const provider of this.languages) { + provider.reInitialize(); + } + } + } + public reloadProjects(): void { this.client.execute('reloadProjects', null, false); this.triggerAllDiagnostics(); diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index 1dc21e9e2b0..3ff2915ab41 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -144,7 +144,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient private _output: OutputChannel; private tsServerLogFile: string | null = null; private tsServerLogLevel: TsServerLogLevel = TsServerLogLevel.Off; - private servicePromise: Promise | null; + private servicePromise: Thenable | null; private lastError: Error | null; private reader: Reader; private sequenceNumber: number; @@ -211,21 +211,8 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient if (this.servicePromise === null && (oldglobalTsdk !== this.globalTsdk || oldLocalTsdk !== this.localTsdk)) { this.startService(); - } else if (this.servicePromise !== null && this.tsServerLogLevel !== oldLoggingLevel) { - - const reloadItem = { title: localize('reloadTitle', 'Reload') }; - window.showInformationMessage( - localize('tsserverLogReloadBlurb', 'Reload VS Code to apply \'typescript.tsserver.log\' change'), - reloadItem, - { - title: localize('later', 'Later'), - isCloseAffordance: true - }) - .then(selected => { - if (selected === reloadItem) { - commands.executeCommand('workbench.action.reloadWindow'); - } - }); + } else if (this.servicePromise !== null && (this.tsServerLogLevel !== oldLoggingLevel || (oldglobalTsdk !== this.globalTsdk || oldLocalTsdk !== this.localTsdk))) { + this.promptUserToRestartTsServer(); } })); if (this.packageInfo && this.packageInfo.aiKey) { @@ -235,6 +222,41 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.startService(); } + public restartTsServer(): void { + const start = () => { + this.trace = this.readTrace(); + this.tsServerLogLevel = this.readTsServerLogLevel(); + this.servicePromise = this.startService(); + return this.servicePromise; + }; + + if (this.servicePromise !== null) { + this.servicePromise = this.servicePromise.then(cp => { + if (cp) { + cp.kill(); + } + }).then(start); + } else { + start(); + } + } + + private promptUserToRestartTsServer(): void { + const restartItem = { title: localize('restartTsServerTitle', 'Restart') }; + window.showInformationMessage( + localize('restartTypeScriptServerBlurb', 'Restart TypeScript Server to apply change'), + restartItem, + { + title: localize('later', 'Later'), + isCloseAffordance: true + }) + .then(selected => { + if (selected === restartItem) { + this.restartTsServer(); + } + }); + } + private extractGlobalTsdk(configuration: WorkspaceConfiguration): string | null { let inspect = configuration.inspect('typescript.tsdk'); if (inspect && inspect.globalValue && 'string' === typeof inspect.globalValue) { @@ -382,7 +404,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient } } - private service(): Promise { + private service(): Thenable { if (this.servicePromise) { return this.servicePromise; } @@ -441,7 +463,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient return !!this.localTsdk; } - private startService(resendModels: boolean = false): void { + private startService(resendModels: boolean = false): Thenable { let modulePath: Thenable = Promise.resolve(this.globalTypescriptPath); if (!this.workspaceState.get(TypeScriptServiceClient.tsdkMigratedStorageKey, false)) { @@ -451,7 +473,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient } } - modulePath.then(modulePath => { + return modulePath.then(modulePath => { if (this.workspaceState.get(TypeScriptServiceClient.useWorkspaceTsdkStorageKey, false)) { if (workspace.rootPath) { // TODO: check if we need better error handling @@ -460,7 +482,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient } return modulePath; }).then(modulePath => { - this.servicePromise = new Promise((resolve, reject) => { + return this.servicePromise = new Promise((resolve, reject) => { const tsConfig = workspace.getConfiguration('typescript'); this.info(`Using tsserver from location: ${modulePath}`); @@ -618,20 +640,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient if (firstRun || newModulePath === this.modulePath) { return; } - - const reloadMessage = { title: localize('reloadTitle', 'Reload') }; - window.showInformationMessage( - localize('reloadBlurb', 'Reload window to apply changes'), - reloadMessage, - { - title: localize('later', 'Later'), - isCloseAffordance: true - }) - .then(selected => { - if (selected === reloadMessage) { - commands.executeCommand('workbench.action.reloadWindow'); - } - }); + this.promptUserToRestartTsServer(); }; return window.showQuickPick(pickOptions, { @@ -681,16 +690,16 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient return window.showErrorMessage( localize( 'typescript.openTsServerLog.loggingNotEnabled', - 'TS Server logging is off. Please set `typescript.tsserver.log` and reload VS Code to enable logging'), + 'TS Server logging is off. Please set `typescript.tsserver.log` and restart the TS server to enable logging'), { title: localize( 'typescript.openTsServerLog.enableAndReloadOption', - 'Enable logging and reload VS Code'), + 'Enable logging and restart TS server'), }) .then(selection => { if (selection) { return workspace.getConfiguration().update('typescript.tsserver.log', 'verbose', true).then(() => { - commands.executeCommand('workbench.action.reloadWindow'); + this.restartTsServer(); return false; }); } @@ -916,16 +925,17 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient this.callbacks[serverRequest.seq] = requestItem.callbacks; this.pendingResponses++; } - this.service().then((childProcess) => { - childProcess.stdin.write(JSON.stringify(serverRequest) + '\r\n', 'utf8'); - }).catch(err => { - let callback = this.callbacks[serverRequest.seq]; - if (callback) { - callback.e(err); - delete this.callbacks[serverRequest.seq]; - this.pendingResponses--; - } - }); + this.service() + .then((childProcess) => { + childProcess.stdin.write(JSON.stringify(serverRequest) + '\r\n', 'utf8'); + }).then(undefined, err => { + let callback = this.callbacks[serverRequest.seq]; + if (callback) { + callback.e(err); + delete this.callbacks[serverRequest.seq]; + this.pendingResponses--; + } + }); } private tryCancelRequest(seq: number): boolean {