From 4cee7cddc84aa3769d5d3e87e5745f4c981bca28 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 22 Feb 2020 20:58:00 +0200 Subject: vscode: gracefully handle cancellation errors --- editors/code/src/ctx.ts | 21 --------------------- editors/code/src/highlighting.ts | 3 ++- editors/code/src/inlay_hints.ts | 40 ++++++++++++++++++---------------------- editors/code/src/util.ts | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 44 deletions(-) (limited to 'editors/code/src') 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 { dispose(): void; } export type Cmd = (...args: any[]) => unknown; - -export async function sendRequestWithRetry( - client: lc.LanguageClient, - method: string, - param: unknown, - token?: vscode.CancellationToken, -): Promise { - for (const delay of [2, 4, 6, 8, 10, null]) { - try { - return await (token ? client.sendRequest(method, param, token) : client.sendRequest(method, param)); - } catch (err) { - if (delay === null || err.code !== lc.ErrorCodes.ContentModified) { - throw err; - } - await sleep(10 * (1 << delay)); - } - } - throw 'unreachable'; -} - -const 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'; import { ColorTheme, TextMateRuleSettings } from './color_theme'; -import { Ctx, sendRequestWithRetry } from './ctx'; +import { Ctx } from './ctx'; +import { sendRequestWithRetry } from './util'; export function activateHighlighting(ctx: Ctx) { 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 @@ import * as vscode from 'vscode'; import * as lc from 'vscode-languageclient'; -import { Ctx, sendRequestWithRetry } from './ctx'; -import { log } from './util'; +import { Ctx } from './ctx'; +import { log, sendRequestWithRetry } from './util'; export function activateInlayHints(ctx: Ctx) { const hintsUpdater = new HintsUpdater(ctx); @@ -152,28 +152,24 @@ class HintsUpdater { } private async queryHints(documentUri: string): Promise { - const client = this.ctx.client; - if (!client) return null; + this.pending.get(documentUri)?.cancel(); - const request: InlayHintsParams = { - textDocument: { uri: documentUri }, - }; const tokenSource = new vscode.CancellationTokenSource(); - const prevHintsRequest = this.pending.get(documentUri); - prevHintsRequest?.cancel(); - this.pending.set(documentUri, tokenSource); - try { - return await sendRequestWithRetry( - client, - 'rust-analyzer/inlayHints', - request, - tokenSource.token, - ); - } finally { - if (!tokenSource.token.isCancellationRequested) { - this.pending.delete(documentUri); - } - } + + const request: InlayHintsParams = { textDocument: { uri: documentUri } }; + + return sendRequestWithRetry( + this.ctx.client, + 'rust-analyzer/inlayHints', + request, + tokenSource.token + ) + .catch(_ => null) + .finally(() => { + if (!tokenSource.token.isCancellationRequested) { + this.pending.delete(documentUri); + } + }); } } 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 @@ +import * as lc from "vscode-languageclient"; +import * as vscode from "vscode"; + let enabled: boolean = false; export const log = { @@ -16,3 +19,40 @@ export const log = { enabled = yes; } }; + +export async function sendRequestWithRetry( + client: lc.LanguageClient, + method: string, + param: unknown, + token?: vscode.CancellationToken, +): Promise { + for (const delay of [2, 4, 6, 8, 10, null]) { + try { + return await (token + ? client.sendRequest(method, param, token) + : client.sendRequest(method, param) + ); + } catch (error) { + if (delay === null) { + log.error("LSP request timed out", { method, param, error }); + throw error; + } + + if (error.code === lc.ErrorCodes.RequestCancelled) { + throw error; + } + + if (error.code !== lc.ErrorCodes.ContentModified) { + log.error("LSP request failed", { method, param, error }); + throw error; + } + + await sleep(10 * (1 << delay)); + } + } + throw 'unreachable'; +} + +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} -- cgit v1.2.3