aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/ctx.ts
diff options
context:
space:
mode:
Diffstat (limited to 'editors/code/src/ctx.ts')
-rw-r--r--editors/code/src/ctx.ts75
1 files changed, 48 insertions, 27 deletions
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index 693ce05ed..13988056a 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -1,21 +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;
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
7 private extCtx: vscode.ExtensionContext; 14 private extCtx: vscode.ExtensionContext;
15 private onDidRestartHooks: Array<(client: lc.LanguageClient) => void> = [];
8 16
9 constructor(extCtx: vscode.ExtensionContext) { 17 constructor(extCtx: vscode.ExtensionContext) {
18 this.config = new Config(extCtx)
10 this.extCtx = extCtx; 19 this.extCtx = extCtx;
11 } 20 }
12 21
13 get client(): lc.LanguageClient { 22 async restartServer() {
14 return Server.client; 23 let old = this.client;
15 } 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();
16 31
17 get config(): Config { 32 this.client = client
18 return Server.config; 33 for (const hook of this.onDidRestartHooks) {
34 hook(client)
35 }
19 } 36 }
20 37
21 get activeRustEditor(): vscode.TextEditor | undefined { 38 get activeRustEditor(): vscode.TextEditor | undefined {
@@ -62,30 +79,34 @@ export class Ctx {
62 this.extCtx.subscriptions.push(d); 79 this.extCtx.subscriptions.push(d);
63 } 80 }
64 81
65 async sendRequestWithRetry<R>( 82 onDidRestart(hook: (client: lc.LanguageClient) => void) {
66 method: string, 83 this.onDidRestartHooks.push(hook)
67 param: any,
68 token?: vscode.CancellationToken,
69 ): Promise<R> {
70 await this.client.onReady();
71 for (const delay of [2, 4, 6, 8, 10, null]) {
72 try {
73 return await (token ? this.client.sendRequest(method, param, token) : this.client.sendRequest(method, param));
74 } catch (e) {
75 if (
76 e.code === lc.ErrorCodes.ContentModified &&
77 delay !== null
78 ) {
79 await sleep(10 * (1 << delay));
80 continue;
81 }
82 throw e;
83 }
84 }
85 throw 'unreachable';
86 } 84 }
87} 85}
88 86
89export type Cmd = (...args: any[]) => any; 87export type Cmd = (...args: any[]) => any;
90 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
91const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); 112const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));