Skip to content

Commit cd01e72

Browse files
bors[bot]Veetaha
andauthored
Merge #3277
3277: vscode: gracefully handle cancellation errors r=matklad a=Veetaha This PR fixes a fleet of errors that rapidly populate the Developer Tools console. ![image](https://user-images.githubusercontent.com/36276403/75097665-0c7aba80-55b6-11ea-8edd-ab5dc5f89e1e.png) Co-authored-by: Veetaha <[email protected]>
2 parents 3d6ec45 + 4cee7cd commit cd01e72

File tree

4 files changed

+60
-44
lines changed

4 files changed

+60
-44
lines changed

editors/code/src/ctx.ts

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,3 @@ export interface Disposable {
5252
dispose(): void;
5353
}
5454
export type Cmd = (...args: any[]) => unknown;
55-
56-
export 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-
75-
const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));

editors/code/src/highlighting.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import * as lc from 'vscode-languageclient';
33

44
import { ColorTheme, TextMateRuleSettings } from './color_theme';
55

6-
import { Ctx, sendRequestWithRetry } from './ctx';
6+
import { Ctx } from './ctx';
7+
import { sendRequestWithRetry } from './util';
78

89
export function activateHighlighting(ctx: Ctx) {
910
const highlighter = new Highlighter(ctx);

editors/code/src/inlay_hints.ts

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as vscode from 'vscode';
22
import * as lc from 'vscode-languageclient';
33

4-
import { Ctx, sendRequestWithRetry } from './ctx';
5-
import { log } from './util';
4+
import { Ctx } from './ctx';
5+
import { log, sendRequestWithRetry } from './util';
66

77
export function activateInlayHints(ctx: Ctx) {
88
const hintsUpdater = new HintsUpdater(ctx);
@@ -152,28 +152,24 @@ class HintsUpdater {
152152
}
153153

154154
private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
155-
const client = this.ctx.client;
156-
if (!client) return null;
155+
this.pending.get(documentUri)?.cancel();
157156

158-
const request: InlayHintsParams = {
159-
textDocument: { uri: documentUri },
160-
};
161157
const tokenSource = new vscode.CancellationTokenSource();
162-
const prevHintsRequest = this.pending.get(documentUri);
163-
prevHintsRequest?.cancel();
164-
165158
this.pending.set(documentUri, tokenSource);
166-
try {
167-
return await sendRequestWithRetry<InlayHint[] | null>(
168-
client,
169-
'rust-analyzer/inlayHints',
170-
request,
171-
tokenSource.token,
172-
);
173-
} finally {
174-
if (!tokenSource.token.isCancellationRequested) {
175-
this.pending.delete(documentUri);
176-
}
177-
}
159+
160+
const request: InlayHintsParams = { textDocument: { uri: documentUri } };
161+
162+
return sendRequestWithRetry<InlayHint[]>(
163+
this.ctx.client,
164+
'rust-analyzer/inlayHints',
165+
request,
166+
tokenSource.token
167+
)
168+
.catch(_ => null)
169+
.finally(() => {
170+
if (!tokenSource.token.isCancellationRequested) {
171+
this.pending.delete(documentUri);
172+
}
173+
});
178174
}
179175
}

editors/code/src/util.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import * as lc from "vscode-languageclient";
2+
import * as vscode from "vscode";
3+
14
let enabled: boolean = false;
25

36
export const log = {
@@ -16,3 +19,40 @@ export const log = {
1619
enabled = yes;
1720
}
1821
};
22+
23+
export 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+
56+
function sleep(ms: number) {
57+
return new Promise(resolve => setTimeout(resolve, ms));
58+
}

0 commit comments

Comments
 (0)