diff --git a/src/canceltokenutils.ts b/src/canceltokenutils.ts new file mode 100644 index 000000000..1a7a6bfbe --- /dev/null +++ b/src/canceltokenutils.ts @@ -0,0 +1,17 @@ +import { CancellationToken, CancellationTokenSource } from 'vscode-jsonrpc' + +export function createTimeoutCancellation(millis: number): CancellationToken { + const source = new CancellationTokenSource() + setTimeout(() => source.cancel(), millis) + return source.token +} + +export function combineCancellationTokens(a: CancellationToken, b: CancellationToken): CancellationToken { + if (a.isCancellationRequested || b.isCancellationRequested) { + return CancellationToken.Cancelled + } + const source = new CancellationTokenSource() + a.onCancellationRequested(() => source.cancel()) + b.onCancellationRequested(() => source.cancel()) + return source.token +} diff --git a/src/interactive/completions.ts b/src/interactive/completions.ts index b4b179d82..898cec98c 100644 --- a/src/interactive/completions.ts +++ b/src/interactive/completions.ts @@ -3,6 +3,7 @@ import * as vscode from 'vscode' import * as rpc from 'vscode-jsonrpc' import { Disposable, MessageConnection } from 'vscode-jsonrpc' +import { combineCancellationTokens, createTimeoutCancellation } from '../canceltokenutils' import { getModuleForEditor } from './modules' import { onExit, onInit } from './repl' @@ -36,42 +37,34 @@ const requestTypeGetCompletionItems = new rpc.RequestType< void >('repl/getcompletions') + function completionItemProvider(conn: MessageConnection): vscode.CompletionItemProvider { return { provideCompletionItems: async (document, position, token, context) => { if (!vscode.workspace.getConfiguration('julia.runtimeCompletions')) { return } - const completionPromise = (async () => { - const startPosition = new vscode.Position(position.line, 0) - const lineRange = new vscode.Range(startPosition, position) - const line = document.getText(lineRange) - const mod: string = await getModuleForEditor(document, position) - return { - items: await conn.sendRequest(requestTypeGetCompletionItems, { line, mod }), - isIncomplete: true - } - })() - const cancelPromise: Promise = new Promise(resolve => { - token.onCancellationRequested(() => resolve({ - items: [], - isIncomplete: true - })) - setTimeout(() => { - if (!token.isCancellationRequested) { - resolve({ - items: [], - isIncomplete: true - }) - } - }, 500) - }) + const newToken = combineCancellationTokens( + token, + createTimeoutCancellation(500) + ) + + const startPosition = new vscode.Position(position.line, 0) + const lineRange = new vscode.Range(startPosition, position) + const line = document.getText(lineRange) + const mod: string = await getModuleForEditor(document, position) // TODO pass newToken once we support tokens in JSONRPC.jl + + if (newToken.isCancellationRequested) { return } - return Promise.race([ - completionPromise, - cancelPromise - ]) + const items = await conn.sendRequest(requestTypeGetCompletionItems, { line, mod }) // TODO pass newToken once we support tokens in JSONRPC.jl + + if (newToken.isCancellationRequested) { return } + + return { + items: items, + isIncomplete: true + } } } }