Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for middleware in onProgress #690

Merged
merged 7 commits into from
Nov 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions client-node-tests/src/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

import * as assert from 'assert';
import * as path from 'path';
import * as lsclient from 'vscode-languageclient/node';
import * as vscode from 'vscode';
import * as lsclient from 'vscode-languageclient/node';

suite('Client integration', () => {

Expand Down Expand Up @@ -271,7 +271,7 @@ suite('Client integration', () => {
isArray(result, vscode.Location, 2);
for (let i = 0; i < result.length; i++) {
const location = result[i];
rangeEqual(location.range, i, i, i ,i);
rangeEqual(location.range, i, i, i, i);
assert.strictEqual(location.uri.toString(), document.uri.toString());
}

Expand Down Expand Up @@ -332,6 +332,42 @@ suite('Client integration', () => {
assert.ok(middlewareCalled);
});

test('Progress', async () => {
const progressToken = 'TEST-PROGRESS-TOKEN';
const middlewareEvents: Array<lsclient.WorkDoneProgressBegin | lsclient.WorkDoneProgressReport | lsclient.WorkDoneProgressEnd> = [];
let currentProgressResolver: () => void | undefined;

// Set up middleware that calls the current resolve function when it gets its 'end' progress event.
middleware.handleWorkDoneProgress = (token: lsclient.ProgressToken, params, next) => {
if (token === progressToken) {
middlewareEvents.push(params);
if (params.kind === 'end')
setImmediate(currentProgressResolver);
}
return next(token, params);
};

// Trigger multiple sample progress events.
for (let i = 0; i < 2; i++) {
await new Promise((resolve) => {
currentProgressResolver = resolve;
client.sendRequest(
new lsclient.ProtocolRequestType<any, null, never, any, any>('testing/sendSampleProgress'),
{},
tokenSource.token,
);
});
}

middleware.handleWorkDoneProgress = undefined;

// Ensure all events were handled.
assert.deepStrictEqual(
middlewareEvents.map((p) => p.kind),
['begin', 'report', 'end', 'begin', 'report', 'end'],
);
});

test('Document Formatting', async () => {
const provider = client.getFeature(lsclient.DocumentFormattingRequest.method).getProvider(document);
isDefined(provider);
Expand Down Expand Up @@ -471,7 +507,7 @@ suite('Client integration', () => {
await provider.provideDocumentColors(document, tokenSource.token);
middleware.provideDocumentColors = undefined;

const presentations = await provider.provideColorPresentations(color.color, { document, range}, tokenSource.token);
const presentations = await provider.provideColorPresentations(color.color, { document, range }, tokenSource.token);

isArray(presentations, vscode.ColorPresentation);
const presentation = presentations[0];
Expand All @@ -481,7 +517,7 @@ suite('Client integration', () => {
middlewareCalled++;
return n(c, x, t);
};
await provider.provideColorPresentations(color.color, { document, range}, tokenSource.token);
await provider.provideColorPresentations(color.color, { document, range }, tokenSource.token);
middleware.provideColorPresentations = undefined;
assert.strictEqual(middlewareCalled, 2);
});
Expand Down Expand Up @@ -562,7 +598,7 @@ suite('Client integration', () => {
assert.strictEqual(middlewareCalled, true);
});

test('Type Definition', async() => {
test('Type Definition', async () => {
const provider = client.getFeature(lsclient.TypeDefinitionRequest.method).getProvider(document);
isDefined(provider);
const result = (await provider.provideTypeDefinition(document, position, tokenSource.token)) as vscode.Location;
Expand Down Expand Up @@ -677,4 +713,4 @@ suite('Client integration', () => {
middleware.provideTypeDefinition = undefined;
assert.strictEqual(middlewareCalled, true);
});
});
});
13 changes: 12 additions & 1 deletion client-node-tests/src/servers/testServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
createConnection, Connection, InitializeParams, ServerCapabilities, CompletionItemKind, ResourceOperationKind, FailureHandlingKind,
DiagnosticTag, CompletionItemTag, TextDocumentSyncKind, MarkupKind, SignatureHelp, SignatureInformation, ParameterInformation,
Location, Range, DocumentHighlight, DocumentHighlightKind, CodeAction, Command, TextEdit, Position, DocumentLink,
ColorInformation, Color, ColorPresentation, FoldingRange, SelectionRange, SymbolKind
ColorInformation, Color, ColorPresentation, FoldingRange, SelectionRange, SymbolKind, ProtocolRequestType, WorkDoneProgress, WorkDoneProgressCreateRequest,
} from '../../../server/node';

import { URI } from 'vscode-uri';
Expand Down Expand Up @@ -284,5 +284,16 @@ connection.languages.onOnTypeRename(() => {
};
});

connection.onRequest(
new ProtocolRequestType<null, null, never, any, any>('testing/sendSampleProgress'),
async (_, __) => {
const progressToken = 'TEST-PROGRESS-TOKEN';
await connection.sendRequest(WorkDoneProgressCreateRequest.type, { token: progressToken });
connection.sendProgress(WorkDoneProgress.type, progressToken, { kind: 'begin', title: 'Test Progress' });
connection.sendProgress(WorkDoneProgress.type, progressToken, { kind: 'report', percentage: 50, message: 'Halfway!' });
connection.sendProgress(WorkDoneProgress.type, progressToken, { kind: 'end', message: 'Completed!' });
},
);

// Listen on the connection
connection.listen();
16 changes: 15 additions & 1 deletion client/src/common/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ import {
DocumentRangeFormattingOptions, DocumentOnTypeFormattingOptions, RenameOptions, DocumentLinkOptions, CompletionItemTag, DiagnosticTag, DocumentColorRequest,
DeclarationRequest, FoldingRangeRequest, ImplementationRequest, SelectionRangeRequest, TypeDefinitionRequest, SymbolTag, CallHierarchyPrepareRequest,
CancellationStrategy, SaveOptions, LSPErrorCodes, CodeActionResolveRequest, RegistrationType, SemanticTokensRegistrationType, InsertTextMode, ShowDocumentRequest,
ShowDocumentParams, ShowDocumentResult, OnTypeRenameRequest
ShowDocumentParams, ShowDocumentResult, OnTypeRenameRequest, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressEnd, WorkDoneProgressReport
} from 'vscode-languageserver-protocol';

import type { ColorProviderMiddleware } from './colorProvider';
Expand Down Expand Up @@ -347,6 +347,10 @@ export interface HandleDiagnosticsSignature {
(this: void, uri: Uri, diagnostics: VDiagnostic[]): void;
}

export interface HandleWorkDoneProgressSignature {
(this: void, token: ProgressToken, params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd): void;
}

export interface ProvideCompletionItemsSignature {
(this: void, document: TextDocument, position: VPosition, context: VCompletionContext, token: CancellationToken): ProviderResult<VCompletionItem[] | VCompletionList>;
}
Expand Down Expand Up @@ -469,6 +473,7 @@ export interface _Middleware {
didClose?: NextSignature<TextDocument, void>;

handleDiagnostics?: (this: void, uri: Uri, diagnostics: VDiagnostic[], next: HandleDiagnosticsSignature) => void;
handleWorkDoneProgress?: (this: void, token: ProgressToken, params: WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd, next: HandleWorkDoneProgressSignature) => void;
provideCompletionItem?: (this: void, document: TextDocument, position: VPosition, context: VCompletionContext, token: CancellationToken, next: ProvideCompletionItemsSignature) => ProviderResult<VCompletionItem[] | VCompletionList>;
resolveCompletionItem?: (this: void, item: VCompletionItem, token: CancellationToken, next: ResolveCompletionItemSignature) => ProviderResult<VCompletionItem>;
provideHover?: (this: void, document: TextDocument, position: VPosition, token: CancellationToken, next: ProvideHoverSignature) => ProviderResult<VHover>;
Expand Down Expand Up @@ -2812,6 +2817,15 @@ export abstract class BaseLanguageClient {
throw new Error('Language client is not ready yet');
}
try {
if (WorkDoneProgress.is(type)) {
const handleWorkDoneProgress = this._clientOptions.middleware!.handleWorkDoneProgress;
if (handleWorkDoneProgress !== undefined) {
return this._resolvedConnection!.onProgress(type, token, (params) => {
handleWorkDoneProgress(token, params, () => handler(params as unknown as P));
});
}
}

return this._resolvedConnection!.onProgress(type, token, handler);
} catch (error) {
this.error(`Registering progress handler for token ${token} failed.`, error);
Expand Down
4 changes: 4 additions & 0 deletions protocol/src/common/protocol.progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ export interface WorkDoneProgressEnd {

export namespace WorkDoneProgress {
export const type = new ProgressType<WorkDoneProgressBegin | WorkDoneProgressReport | WorkDoneProgressEnd>();

export function is(value: ProgressType<any>): value is typeof type {
return value === type;
}
}

export interface WorkDoneProgressCreateParams {
Expand Down