// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. import { v4 } from "uuid"; import { CancellationToken, CancellationTokenSource, Disposable, EventEmitter, ProgressLocation, StatusBarAlignment, StatusBarItem, window, workspace } from "vscode"; import { IProgressProvider, IProgressReporter } from "./progressAPI"; const STATUS_COMMAND: string = "java.show.server.task.status"; class ProgressReporter implements IProgressReporter { private _id: string = v4(); private _jobName: string; private _progressLocation: ProgressLocation | { viewId: string }; private _cancellable: boolean = false; private _message: string; private _increment: number | undefined; private _isShown: boolean; private _tokenSource = new CancellationTokenSource(); private _statusBarItem: StatusBarItem | undefined; private _cancelProgressEventEmitter: EventEmitter; private _progressEventEmitter: EventEmitter; private _disposables: Disposable[] = []; constructor(jobName: string, progressLocation: ProgressLocation | { viewId: string }, cancellable: boolean) { this._jobName = jobName; this._progressLocation = progressLocation || ProgressLocation.Notification; this._cancellable = cancellable; const config = workspace.getConfiguration("java"); if (config.silentNotification && this._progressLocation === ProgressLocation.Notification) { this._progressLocation = ProgressLocation.Window; } if (this._progressLocation === ProgressLocation.Window) { this._statusBarItem = window.createStatusBarItem(this._id, StatusBarAlignment.Left, 1); this._statusBarItem.name = "Progress Message for " + this._jobName; this._statusBarItem.text = `$(sync~spin) ${this._jobName}...`; this._statusBarItem.command = { title: "Check Java Build Status", command: STATUS_COMMAND, arguments: [], }; this._statusBarItem.tooltip = "Check Java Build Status"; this._disposables.push(this._statusBarItem); } this._cancelProgressEventEmitter = new EventEmitter(); this._progressEventEmitter = new EventEmitter(); this._disposables.push(this._cancelProgressEventEmitter); this._disposables.push(this._progressEventEmitter); this._disposables.push(this._tokenSource); } public setJobName(jobName: string): void { this._jobName = jobName; } public getId(): string { return this._id; } public getProgressLocation(): ProgressLocation | { viewId: string } { return this._progressLocation; } public report(message: string, increment?: number): void { if (this._statusBarItem) { const text = message ? `${this._jobName} - ${message}` : `${this._jobName}...`; this._statusBarItem.text = `$(sync~spin) ${text}`; } this._message = message; this._increment = increment; this._progressEventEmitter.fire(); this.show(); } public show(): void { if (this._statusBarItem) { this._statusBarItem.show(); return; } this.showNativeProgress(); } public hide(onlyNotifications?: boolean): void { if (onlyNotifications && this._progressLocation === ProgressLocation.Notification) { this._cancelProgressEventEmitter.fire(); this._isShown = false; } } public isCancelled(): boolean { return this.getCancellationToken().isCancellationRequested; } public done(): void { this._tokenSource.cancel(); this._cancelProgressEventEmitter.fire(); this._statusBarItem?.hide(); this._disposables.forEach((disposable) => disposable.dispose()); ( progressProvider).remove(this); } public getCancellationToken(): CancellationToken { return this._tokenSource.token; } public observe(token?: CancellationToken): void { token?.onCancellationRequested(() => { this.done(); }); } private showNativeProgress() { if (this._isShown) { return; } this._isShown = true; window.withProgress({ location: this._progressLocation, title: this._jobName ? `[${this._jobName}](command:${STATUS_COMMAND})` : undefined, cancellable: this._cancellable, }, (progress, token) => { progress.report({ message: this._message, increment: this._increment, }); this.observe(token); this._progressEventEmitter.event(() => { progress.report({ message: this._message, increment: this._increment, }); }); return new Promise((resolve) => { this._cancelProgressEventEmitter.event(() => { resolve(true); }); }); }); } } class ProgressProvider implements IProgressProvider { private store: { [key: string]: IProgressReporter } = {}; public createProgressReporter(jobName: string, progressLocation?: ProgressLocation | { viewId: string }, cancellable?: boolean): IProgressReporter { const progressReporter = new ProgressReporter(jobName, progressLocation || ProgressLocation.Notification, cancellable === undefined ? true : !!cancellable); this.store[progressReporter.getId()] = progressReporter; return progressReporter; } public getProgressReporter(progressId: string): IProgressReporter | undefined { return this.store[progressId]; } public remove(progressReporter: IProgressReporter) { delete this.store[progressReporter.getId()]; } } export const progressProvider: IProgressProvider = new ProgressProvider();