Skip to content

Commit 295aaa3

Browse files
authored
Round progress percentage according to the spec (#1413)
Round progress to match the spec
1 parent c0982bf commit 295aaa3

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

client-node-tests/src/integration.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,40 @@ suite('Client integration', () => {
566566
);
567567
});
568568

569+
test('Progress percentage is an integer', async () => {
570+
const progressToken = 'TEST-PROGRESS-PERCENTAGE';
571+
const percentages: Array<number | undefined> = [];
572+
let currentProgressResolver: (value: unknown) => void | undefined;
573+
574+
// Set up middleware that calls the current resolve function when it gets its 'end' progress event.
575+
middleware.handleWorkDoneProgress = (token: lsclient.ProgressToken, params: lsclient.WorkDoneProgressBegin | lsclient.WorkDoneProgressReport | lsclient.WorkDoneProgressEnd, next) => {
576+
if (token === progressToken) {
577+
const percentage = params.kind === 'report' || params.kind === 'begin' ? params.percentage : undefined;
578+
percentages.push(percentage);
579+
580+
if (params.kind === 'end') {
581+
setImmediate(currentProgressResolver);
582+
}
583+
}
584+
return next(token, params);
585+
};
586+
587+
// Trigger a progress event.
588+
await new Promise<unknown>((resolve) => {
589+
currentProgressResolver = resolve;
590+
void client.sendRequest(
591+
new lsclient.ProtocolRequestType<any, null, never, any, any>('testing/sendSampleProgress'),
592+
{},
593+
tokenSource.token,
594+
);
595+
});
596+
597+
middleware.handleWorkDoneProgress = undefined;
598+
599+
// Ensure percentages are rounded according to the spec
600+
assert.deepStrictEqual(percentages, [0, 50, undefined]);
601+
});
602+
569603
test('Document Formatting', async () => {
570604
const provider = client.getFeature(lsclient.DocumentFormattingRequest.method).getProvider(document);
571605
isDefined(provider);

client-node-tests/src/servers/testServer.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,14 @@ connection.onRequest(
530530
void connection.sendProgress(WorkDoneProgress.type, progressToken, { kind: 'begin', title: 'Test Progress' });
531531
void connection.sendProgress(WorkDoneProgress.type, progressToken, { kind: 'report', percentage: 50, message: 'Halfway!' });
532532
void connection.sendProgress(WorkDoneProgress.type, progressToken, { kind: 'end', message: 'Completed!' });
533+
534+
// According to the spec, the reported percentage has to be an integer.
535+
// Because JS doesn't have integer support, we have rounding code in place.
536+
const progressToken2 = 'TEST-PROGRESS-PERCENTAGE';
537+
const progress = connection.window.attachWorkDoneProgress(progressToken2);
538+
progress.begin('Test Progress', 0.1);
539+
progress.report(49.9, 'Halfway!');
540+
progress.done();
533541
},
534542
);
535543

server/src/common/progress.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,14 @@ class WorkDoneProgressReporterImpl implements WorkDoneProgressReporter {
4747
const param: WorkDoneProgressBegin = {
4848
kind: 'begin',
4949
title,
50-
percentage,
5150
message,
5251
cancellable
5352
};
53+
if (typeof percentage === 'number') {
54+
// Round to the nearest integer, because the percentage
55+
// is a uinteger according to the specification
56+
param.percentage = Math.round(percentage);
57+
}
5458
this._connection.sendProgress(WorkDoneProgress.type, this._token, param);
5559
}
5660

@@ -59,7 +63,9 @@ class WorkDoneProgressReporterImpl implements WorkDoneProgressReporter {
5963
kind: 'report'
6064
};
6165
if (typeof arg0 === 'number') {
62-
param.percentage = arg0;
66+
// Round to the nearest integer, because the percentage
67+
// is a uinteger according to the specification
68+
param.percentage = Math.round(arg0);
6369
if (arg1 !== undefined) {
6470
param.message = arg1;
6571
}

0 commit comments

Comments
 (0)