forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstatusProvider.ts
More file actions
117 lines (100 loc) · 4.09 KB
/
statusProvider.ts
File metadata and controls
117 lines (100 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
'use strict';
import { inject, injectable } from 'inversify';
import { Disposable, ProgressLocation, ProgressOptions } from 'vscode';
import { IApplicationShell } from '../common/application/types';
import { createDeferred, Deferred } from '../common/utils/async';
import { IInteractiveWindowProvider, IStatusProvider } from './types';
class StatusItem implements Disposable {
private deferred: Deferred<void>;
private disposed: boolean = false;
private timeout: NodeJS.Timer | number | undefined;
private disposeCallback: () => void;
constructor(_title: string, disposeCallback: () => void, timeout?: number) {
this.deferred = createDeferred<void>();
this.disposeCallback = disposeCallback;
// A timeout is possible too. Auto dispose if that's the case
if (timeout) {
this.timeout = setTimeout(this.dispose, timeout);
}
}
public dispose = () => {
if (!this.disposed) {
this.disposed = true;
if (this.timeout) {
// tslint:disable-next-line: no-any
clearTimeout(this.timeout as any);
this.timeout = undefined;
}
this.disposeCallback();
if (!this.deferred.completed) {
this.deferred.resolve();
}
}
}
public promise = (): Promise<void> => {
return this.deferred.promise;
}
public reject = () => {
this.deferred.reject();
this.dispose();
}
}
@injectable()
export class StatusProvider implements IStatusProvider {
private statusCount: number = 0;
constructor(@inject(IApplicationShell) private applicationShell: IApplicationShell, @inject(IInteractiveWindowProvider) private interactiveWindowProvider: IInteractiveWindowProvider) {}
public set(message: string, timeout?: number, cancel?: () => void, skipHistory?: boolean): Disposable {
// Start our progress
this.incrementCount(skipHistory);
// Create a StatusItem that will return our promise
const statusItem = new StatusItem(message, () => this.decrementCount(skipHistory), timeout);
const progressOptions: ProgressOptions = {
location: cancel ? ProgressLocation.Notification : ProgressLocation.Window,
title: message,
cancellable: cancel !== undefined
};
// Set our application shell status with a busy icon
this.applicationShell.withProgress(progressOptions, (_p, c) => {
if (c && cancel) {
c.onCancellationRequested(() => {
cancel();
statusItem.reject();
});
}
return statusItem.promise();
});
return statusItem;
}
public async waitWithStatus<T>(promise: () => Promise<T>, message: string, timeout?: number, cancel?: () => void, skipHistory?: boolean): Promise<T> {
// Create a status item and wait for our promise to either finish or reject
const status = this.set(message, timeout, cancel, skipHistory);
let result: T;
try {
result = await promise();
} finally {
status.dispose();
}
return result;
}
private incrementCount = (skipHistory?: boolean) => {
if (this.statusCount === 0) {
const history = this.interactiveWindowProvider.getActive();
if (history && !skipHistory) {
history.startProgress();
}
}
this.statusCount += 1;
}
private decrementCount = (skipHistory?: boolean) => {
const updatedCount = this.statusCount - 1;
if (updatedCount === 0) {
const history = this.interactiveWindowProvider.getActive();
if (history && !skipHistory) {
history.stopProgress();
}
}
this.statusCount = Math.max(updatedCount, 0);
}
}