vscode-java-debug/src/progressImpl.ts

164 lines
5.8 KiB
TypeScript

// 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<void>;
private _progressEventEmitter: EventEmitter<void>;
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(StatusBarAlignment.Left, 1);
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<any>();
this._progressEventEmitter = new EventEmitter<any>();
this._disposables.push(this._cancelProgressEventEmitter);
this._disposables.push(this._progressEventEmitter);
this._disposables.push(this._tokenSource);
}
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> 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<boolean>({
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();