From 087af54069d34eef5197e04d64ac322d9ee98085 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 31 Dec 2019 18:14:00 +0100 Subject: Refactor server lifecycle --- editors/code/src/ctx.ts | 76 ++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 29 deletions(-) (limited to 'editors/code/src/ctx.ts') diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts index 393d6a602..13988056a 100644 --- a/editors/code/src/ctx.ts +++ b/editors/code/src/ctx.ts @@ -1,19 +1,38 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; -import { Server } from './server'; import { Config } from './config'; +import { createClient } from './client' export class Ctx { readonly config: Config; + // Because we have "reload server" action, various listeners **will** face a + // situation where the client is not ready yet, and should be prepared to + // deal with it. + // + // Ideally, this should be replaced with async getter though. + client: lc.LanguageClient | null = null private extCtx: vscode.ExtensionContext; + private onDidRestartHooks: Array<(client: lc.LanguageClient) => void> = []; constructor(extCtx: vscode.ExtensionContext) { this.config = new Config(extCtx) this.extCtx = extCtx; } - get client(): lc.LanguageClient { - return Server.client; + async restartServer() { + let old = this.client; + if (old) { + await old.stop() + } + this.client = null; + const client = createClient(this.config); + this.pushCleanup(client.start()); + await client.onReady(); + + this.client = client + for (const hook of this.onDidRestartHooks) { + hook(client) + } } get activeRustEditor(): vscode.TextEditor | undefined { @@ -60,35 +79,34 @@ export class Ctx { this.extCtx.subscriptions.push(d); } - async sendRequestWithRetry( - method: string, - param: any, - token?: vscode.CancellationToken, - ): Promise { - await this.client.onReady(); - for (const delay of [2, 4, 6, 8, 10, null]) { - try { - return await (token ? this.client.sendRequest(method, param, token) : this.client.sendRequest(method, param)); - } catch (e) { - if ( - e.code === lc.ErrorCodes.ContentModified && - delay !== null - ) { - await sleep(10 * (1 << delay)); - continue; - } - throw e; - } - } - throw 'unreachable'; - } - - onNotification(method: string, handler: lc.GenericNotificationHandler) { - this.client.onReady() - .then(() => this.client.onNotification(method, handler)) + onDidRestart(hook: (client: lc.LanguageClient) => void) { + this.onDidRestartHooks.push(hook) } } export type Cmd = (...args: any[]) => any; +export async function sendRequestWithRetry( + client: lc.LanguageClient, + method: string, + param: any, + token?: vscode.CancellationToken, +): Promise { + for (const delay of [2, 4, 6, 8, 10, null]) { + try { + return await (token ? client.sendRequest(method, param, token) : client.sendRequest(method, param)); + } catch (e) { + if ( + e.code === lc.ErrorCodes.ContentModified && + delay !== null + ) { + await sleep(10 * (1 << delay)); + continue; + } + throw e; + } + } + throw 'unreachable'; +} + const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); -- cgit v1.2.3