aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/ctx.ts
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2019-12-31 17:14:00 +0000
committerAleksey Kladov <[email protected]>2019-12-31 17:32:17 +0000
commit087af54069d34eef5197e04d64ac322d9ee98085 (patch)
tree3a6e4b1884930c07bd800a771ffd777d7a866b11 /editors/code/src/ctx.ts
parent0849f7001cac6af93ce9e9356f8c21881bbe34c5 (diff)
Refactor server lifecycle
Diffstat (limited to 'editors/code/src/ctx.ts')
-rw-r--r--editors/code/src/ctx.ts76
1 files changed, 47 insertions, 29 deletions
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 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3import { Server } from './server';
4import { Config } from './config'; 3import { Config } from './config';
4import { createClient } from './client'
5 5
6export class Ctx { 6export class Ctx {
7 readonly config: Config; 7 readonly config: Config;
8 // Because we have "reload server" action, various listeners **will** face a
9 // situation where the client is not ready yet, and should be prepared to
10 // deal with it.
11 //
12 // Ideally, this should be replaced with async getter though.
13 client: lc.LanguageClient | null = null
8 private extCtx: vscode.ExtensionContext; 14 private extCtx: vscode.ExtensionContext;
15 private onDidRestartHooks: Array<(client: lc.LanguageClient) => void> = [];
9 16
10 constructor(extCtx: vscode.ExtensionContext) { 17 constructor(extCtx: vscode.ExtensionContext) {
11 this.config = new Config(extCtx) 18 this.config = new Config(extCtx)
12 this.extCtx = extCtx; 19 this.extCtx = extCtx;
13 } 20 }
14 21
15 get client(): lc.LanguageClient { 22 async restartServer() {
16 return Server.client; 23 let old = this.client;
24 if (old) {
25 await old.stop()
26 }
27 this.client = null;
28 const client = createClient(this.config);
29 this.pushCleanup(client.start());
30 await client.onReady();
31
32 this.client = client
33 for (const hook of this.onDidRestartHooks) {
34 hook(client)
35 }
17 } 36 }
18 37
19 get activeRustEditor(): vscode.TextEditor | undefined { 38 get activeRustEditor(): vscode.TextEditor | undefined {
@@ -60,35 +79,34 @@ export class Ctx {
60 this.extCtx.subscriptions.push(d); 79 this.extCtx.subscriptions.push(d);
61 } 80 }
62 81
63 async sendRequestWithRetry<R>( 82 onDidRestart(hook: (client: lc.LanguageClient) => void) {
64 method: string, 83 this.onDidRestartHooks.push(hook)
65 param: any,
66 token?: vscode.CancellationToken,
67 ): Promise<R> {
68 await this.client.onReady();
69 for (const delay of [2, 4, 6, 8, 10, null]) {
70 try {
71 return await (token ? this.client.sendRequest(method, param, token) : this.client.sendRequest(method, param));
72 } catch (e) {
73 if (
74 e.code === lc.ErrorCodes.ContentModified &&
75 delay !== null
76 ) {
77 await sleep(10 * (1 << delay));
78 continue;
79 }
80 throw e;
81 }
82 }
83 throw 'unreachable';
84 }
85
86 onNotification(method: string, handler: lc.GenericNotificationHandler) {
87 this.client.onReady()
88 .then(() => this.client.onNotification(method, handler))
89 } 84 }
90} 85}
91 86
92export type Cmd = (...args: any[]) => any; 87export type Cmd = (...args: any[]) => any;
93 88
89export async function sendRequestWithRetry<R>(
90 client: lc.LanguageClient,
91 method: string,
92 param: any,
93 token?: vscode.CancellationToken,
94): Promise<R> {
95 for (const delay of [2, 4, 6, 8, 10, null]) {
96 try {
97 return await (token ? client.sendRequest(method, param, token) : client.sendRequest(method, param));
98 } catch (e) {
99 if (
100 e.code === lc.ErrorCodes.ContentModified &&
101 delay !== null
102 ) {
103 await sleep(10 * (1 << delay));
104 continue;
105 }
106 throw e;
107 }
108 }
109 throw 'unreachable';
110}
111
94const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); 112const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));