aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
authorVeetaha <[email protected]>2020-02-22 18:58:00 +0000
committerVeetaha <[email protected]>2020-02-23 13:49:09 +0000
commit4cee7cddc84aa3769d5d3e87e5745f4c981bca28 (patch)
treef8b98268925cf01e2cc74a9e12fac81a460c1eff /editors
parent838ad6bcfb2a82c030e18d019b8a06752f0fc828 (diff)
vscode: gracefully handle cancellation errors
Diffstat (limited to 'editors')
-rw-r--r--editors/code/src/ctx.ts21
-rw-r--r--editors/code/src/highlighting.ts3
-rw-r--r--editors/code/src/inlay_hints.ts40
-rw-r--r--editors/code/src/util.ts40
4 files changed, 60 insertions, 44 deletions
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index dfc8aa7b9..43540e0d8 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -52,24 +52,3 @@ export interface Disposable {
52 dispose(): void; 52 dispose(): void;
53} 53}
54export type Cmd = (...args: any[]) => unknown; 54export type Cmd = (...args: any[]) => unknown;
55
56export async function sendRequestWithRetry<R>(
57 client: lc.LanguageClient,
58 method: string,
59 param: unknown,
60 token?: vscode.CancellationToken,
61): Promise<R> {
62 for (const delay of [2, 4, 6, 8, 10, null]) {
63 try {
64 return await (token ? client.sendRequest(method, param, token) : client.sendRequest(method, param));
65 } catch (err) {
66 if (delay === null || err.code !== lc.ErrorCodes.ContentModified) {
67 throw err;
68 }
69 await sleep(10 * (1 << delay));
70 }
71 }
72 throw 'unreachable';
73}
74
75const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts
index b34e49c17..77b4a1a68 100644
--- a/editors/code/src/highlighting.ts
+++ b/editors/code/src/highlighting.ts
@@ -3,7 +3,8 @@ import * as lc from 'vscode-languageclient';
3 3
4import { ColorTheme, TextMateRuleSettings } from './color_theme'; 4import { ColorTheme, TextMateRuleSettings } from './color_theme';
5 5
6import { Ctx, sendRequestWithRetry } from './ctx'; 6import { Ctx } from './ctx';
7import { sendRequestWithRetry } from './util';
7 8
8export function activateHighlighting(ctx: Ctx) { 9export function activateHighlighting(ctx: Ctx) {
9 const highlighter = new Highlighter(ctx); 10 const highlighter = new Highlighter(ctx);
diff --git a/editors/code/src/inlay_hints.ts b/editors/code/src/inlay_hints.ts
index 7e6c310a9..5f9229efb 100644
--- a/editors/code/src/inlay_hints.ts
+++ b/editors/code/src/inlay_hints.ts
@@ -1,8 +1,8 @@
1import * as vscode from 'vscode'; 1import * as vscode from 'vscode';
2import * as lc from 'vscode-languageclient'; 2import * as lc from 'vscode-languageclient';
3 3
4import { Ctx, sendRequestWithRetry } from './ctx'; 4import { Ctx } from './ctx';
5import { log } from './util'; 5import { log, sendRequestWithRetry } from './util';
6 6
7export function activateInlayHints(ctx: Ctx) { 7export function activateInlayHints(ctx: Ctx) {
8 const hintsUpdater = new HintsUpdater(ctx); 8 const hintsUpdater = new HintsUpdater(ctx);
@@ -152,28 +152,24 @@ class HintsUpdater {
152 } 152 }
153 153
154 private async queryHints(documentUri: string): Promise<InlayHint[] | null> { 154 private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
155 const client = this.ctx.client; 155 this.pending.get(documentUri)?.cancel();
156 if (!client) return null;
157 156
158 const request: InlayHintsParams = {
159 textDocument: { uri: documentUri },
160 };
161 const tokenSource = new vscode.CancellationTokenSource(); 157 const tokenSource = new vscode.CancellationTokenSource();
162 const prevHintsRequest = this.pending.get(documentUri);
163 prevHintsRequest?.cancel();
164
165 this.pending.set(documentUri, tokenSource); 158 this.pending.set(documentUri, tokenSource);
166 try { 159
167 return await sendRequestWithRetry<InlayHint[] | null>( 160 const request: InlayHintsParams = { textDocument: { uri: documentUri } };
168 client, 161
169 'rust-analyzer/inlayHints', 162 return sendRequestWithRetry<InlayHint[]>(
170 request, 163 this.ctx.client,
171 tokenSource.token, 164 'rust-analyzer/inlayHints',
172 ); 165 request,
173 } finally { 166 tokenSource.token
174 if (!tokenSource.token.isCancellationRequested) { 167 )
175 this.pending.delete(documentUri); 168 .catch(_ => null)
176 } 169 .finally(() => {
177 } 170 if (!tokenSource.token.isCancellationRequested) {
171 this.pending.delete(documentUri);
172 }
173 });
178 } 174 }
179} 175}
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 7a6657753..2f18f85a3 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -1,3 +1,6 @@
1import * as lc from "vscode-languageclient";
2import * as vscode from "vscode";
3
1let enabled: boolean = false; 4let enabled: boolean = false;
2 5
3export const log = { 6export const log = {
@@ -16,3 +19,40 @@ export const log = {
16 enabled = yes; 19 enabled = yes;
17 } 20 }
18}; 21};
22
23export async function sendRequestWithRetry<R>(
24 client: lc.LanguageClient,
25 method: string,
26 param: unknown,
27 token?: vscode.CancellationToken,
28): Promise<R> {
29 for (const delay of [2, 4, 6, 8, 10, null]) {
30 try {
31 return await (token
32 ? client.sendRequest(method, param, token)
33 : client.sendRequest(method, param)
34 );
35 } catch (error) {
36 if (delay === null) {
37 log.error("LSP request timed out", { method, param, error });
38 throw error;
39 }
40
41 if (error.code === lc.ErrorCodes.RequestCancelled) {
42 throw error;
43 }
44
45 if (error.code !== lc.ErrorCodes.ContentModified) {
46 log.error("LSP request failed", { method, param, error });
47 throw error;
48 }
49
50 await sleep(10 * (1 << delay));
51 }
52 }
53 throw 'unreachable';
54}
55
56function sleep(ms: number) {
57 return new Promise(resolve => setTimeout(resolve, ms));
58}