extHostProgress.ts 3.5 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import { ProgressOptions } from 'vscode';
J
Johannes Rieken 已提交
7
import { MainThreadProgressShape, ExtHostProgressShape } from './extHost.protocol';
J
Johannes Rieken 已提交
8
import { ProgressLocation } from './extHostTypeConverters';
9
import { Progress, IProgressStep } from 'vs/platform/progress/common/progress';
10 11
import { localize } from 'vs/nls';
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
12
import { debounce } from 'vs/base/common/decorators';
13
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
14

15
export class ExtHostProgress implements ExtHostProgressShape {
16 17 18

	private _proxy: MainThreadProgressShape;
	private _handles: number = 0;
19
	private _mapHandleToCancellationSource: Map<number, CancellationTokenSource> = new Map();
20 21 22 23 24

	constructor(proxy: MainThreadProgressShape) {
		this._proxy = proxy;
	}

J
Johannes Rieken 已提交
25
	withProgress<R>(extension: IExtensionDescription, options: ProgressOptions, task: (progress: Progress<IProgressStep>, token: CancellationToken) => Thenable<R>): Thenable<R> {
26
		const handle = this._handles++;
27 28 29
		const { title, location, cancellable } = options;
		const source = localize('extensionSource', "{0} (Extension)", extension.displayName || extension.name);
		this._proxy.$startProgress(handle, { location: ProgressLocation.from(location), title, source, cancellable });
M
Matt Bierner 已提交
30
		return this._withProgress(handle, task, !!cancellable);
31 32
	}

33
	private _withProgress<R>(handle: number, task: (progress: Progress<IProgressStep>, token: CancellationToken) => Thenable<R>, cancellable: boolean): Thenable<R> {
M
Matt Bierner 已提交
34
		let source: CancellationTokenSource | undefined;
35 36 37 38
		if (cancellable) {
			source = new CancellationTokenSource();
			this._mapHandleToCancellationSource.set(handle, source);
		}
39

40 41 42 43 44 45 46 47
		const progressEnd = (handle: number): void => {
			this._proxy.$progressEnd(handle);
			this._mapHandleToCancellationSource.delete(handle);
			if (source) {
				source.dispose();
			}
		};

48 49 50
		let p: Thenable<R>;

		try {
M
Matt Bierner 已提交
51
			p = task(new ProgressCallback(this._proxy, handle), cancellable && source ? source.token : CancellationToken.None);
52
		} catch (err) {
53
			progressEnd(handle);
54 55 56
			throw err;
		}

57
		p.then(result => progressEnd(handle), err => progressEnd(handle));
58
		return p;
59
	}
60 61 62 63 64 65 66 67

	public $acceptProgressCanceled(handle: number): void {
		const source = this._mapHandleToCancellationSource.get(handle);
		if (source) {
			source.cancel();
			this._mapHandleToCancellationSource.delete(handle);
		}
	}
68
}
J
Johannes Rieken 已提交
69

70 71 72
function mergeProgress(result: IProgressStep, currentValue: IProgressStep): IProgressStep {
	result.message = currentValue.message;
	if (typeof currentValue.increment === 'number') {
B
Benjamin Pasero 已提交
73 74 75 76 77
		if (typeof result.increment === 'number') {
			result.increment += currentValue.increment;
		} else {
			result.increment = currentValue.increment;
		}
78 79 80 81
	}

	return result;
}
B
Benjamin Pasero 已提交
82

83
class ProgressCallback extends Progress<IProgressStep> {
84 85 86 87
	constructor(private _proxy: MainThreadProgressShape, private _handle: number) {
		super(p => this.throttledReport(p));
	}

88 89 90
	@debounce(100, (result: IProgressStep, currentValue: IProgressStep) => mergeProgress(result, currentValue), () => Object.create(null))
	throttledReport(p: IProgressStep): void {
		this._proxy.$progressReport(this._handle, p);
91
	}
J
Johannes Rieken 已提交
92
}