diff options
Diffstat (limited to 'editors/code/src/ctx.ts')
-rw-r--r-- | editors/code/src/ctx.ts | 75 |
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 @@ | |||
1 | import * as vscode from 'vscode'; | 1 | import * as vscode from 'vscode'; |
2 | import * as lc from 'vscode-languageclient'; | 2 | import * as lc from 'vscode-languageclient'; |
3 | import { Server } from './server'; | ||
4 | import { Config } from './config'; | 3 | import { Config } from './config'; |
4 | import { createClient } from './client' | ||
5 | 5 | ||
6 | export class Ctx { | 6 | export 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 | ||
89 | export type Cmd = (...args: any[]) => any; | 87 | export type Cmd = (...args: any[]) => any; |
90 | 88 | ||
89 | export 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 | |||
91 | const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); | 112 | const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); |