@opensumi/ide-utils 2.21.13 → 2.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/arrays.d.ts +3 -3
- package/lib/arrays.d.ts.map +1 -1
- package/lib/arrays.js.map +1 -1
- package/lib/async.d.ts +3 -3
- package/lib/async.d.ts.map +1 -1
- package/lib/buffer.js +4 -4
- package/lib/buffer.js.map +1 -1
- package/lib/character-classifier.js +3 -3
- package/lib/character-classifier.js.map +1 -1
- package/lib/decorators.d.ts +1 -1
- package/lib/decorators.d.ts.map +1 -1
- package/lib/encoding.d.ts +7 -1
- package/lib/encoding.d.ts.map +1 -1
- package/lib/encoding.js +15 -2
- package/lib/encoding.js.map +1 -1
- package/lib/errors.d.ts +2 -2
- package/lib/errors.d.ts.map +1 -1
- package/lib/event.d.ts +2 -2
- package/lib/event.d.ts.map +1 -1
- package/lib/filters.d.ts +3 -3
- package/lib/filters.d.ts.map +1 -1
- package/lib/filters.js +25 -25
- package/lib/filters.js.map +1 -1
- package/lib/glob.d.ts +2 -2
- package/lib/glob.d.ts.map +1 -1
- package/lib/glob.js +1 -1
- package/lib/glob.js.map +1 -1
- package/lib/hash.js +10 -10
- package/lib/hash.js.map +1 -1
- package/lib/iterator.d.ts +1 -1
- package/lib/iterator.d.ts.map +1 -1
- package/lib/linked-text.d.ts +1 -1
- package/lib/linked-text.d.ts.map +1 -1
- package/lib/linked-text.js.map +1 -1
- package/lib/map.js +17 -17
- package/lib/map.js.map +1 -1
- package/lib/objects.d.ts +1 -0
- package/lib/objects.d.ts.map +1 -1
- package/lib/objects.js +38 -1
- package/lib/objects.js.map +1 -1
- package/lib/os.d.ts +1 -8
- package/lib/os.d.ts.map +1 -1
- package/lib/os.js +4 -8
- package/lib/os.js.map +1 -1
- package/lib/path.d.ts +1 -1
- package/lib/path.d.ts.map +1 -1
- package/lib/path.js +29 -29
- package/lib/path.js.map +1 -1
- package/lib/platform.js +8 -8
- package/lib/platform.js.map +1 -1
- package/lib/process.d.ts.map +1 -1
- package/lib/process.js +28 -13
- package/lib/process.js.map +1 -1
- package/lib/progress.js +3 -3
- package/lib/progress.js.map +1 -1
- package/lib/strings.js +9 -9
- package/lib/strings.js.map +1 -1
- package/lib/types.d.ts +5 -1
- package/lib/types.d.ts.map +1 -1
- package/lib/types.js +8 -1
- package/lib/types.js.map +1 -1
- package/lib/uint.js +4 -4
- package/lib/uint.js.map +1 -1
- package/lib/uri.js +8 -8
- package/lib/uri.js.map +1 -1
- package/lib/uuid.d.ts +1 -1
- package/lib/uuid.d.ts.map +1 -1
- package/lib/uuid.js +3 -2
- package/lib/uuid.js.map +1 -1
- package/package.json +8 -6
- package/src/ansi.ts +10 -0
- package/src/argv.ts +57 -0
- package/src/arrays.ts +328 -0
- package/src/async.ts +580 -0
- package/src/buffer.ts +290 -0
- package/src/cache.ts +37 -0
- package/src/cancellation.ts +136 -0
- package/src/charCode.ts +425 -0
- package/src/character-classifier.ts +82 -0
- package/src/const/encoding.ts +242 -0
- package/src/const/index.ts +1 -0
- package/src/date.ts +36 -0
- package/src/decorators.ts +166 -0
- package/src/disposable.ts +377 -0
- package/src/encoding.ts +278 -0
- package/src/errors.ts +192 -0
- package/src/event.ts +1024 -0
- package/src/file-uri.ts +41 -0
- package/src/filters.ts +887 -0
- package/src/functional.ts +43 -0
- package/src/glob.ts +752 -0
- package/src/hash.ts +336 -0
- package/src/iconLabels.ts +149 -0
- package/src/index.ts +40 -0
- package/src/iterator.ts +36 -0
- package/src/lifecycle.ts +48 -0
- package/src/linked-list.ts +144 -0
- package/src/linked-text.ts +55 -0
- package/src/lru-map.ts +133 -0
- package/src/map.ts +934 -0
- package/src/marshalling.ts +62 -0
- package/src/objects.ts +145 -0
- package/src/os.ts +76 -0
- package/src/path.ts +1885 -0
- package/src/platform.ts +194 -0
- package/src/process.ts +43 -0
- package/src/progress.ts +83 -0
- package/src/promises.ts +23 -0
- package/src/sequence.ts +28 -0
- package/src/strings.ts +1002 -0
- package/src/types.ts +214 -0
- package/src/uint.ts +59 -0
- package/src/uri.ts +298 -0
- package/src/uuid.ts +6 -0
package/src/async.ts
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
import { CancellationToken, CancellationTokenSource } from './cancellation';
|
|
2
|
+
import { IDisposable, toDisposable } from './disposable';
|
|
3
|
+
import { canceled } from './errors';
|
|
4
|
+
|
|
5
|
+
export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>;
|
|
6
|
+
|
|
7
|
+
export interface CancelablePromise<T> extends Promise<T> {
|
|
8
|
+
cancel(): void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function createCancelablePromise<T>(callback: (token: CancellationToken) => Promise<T>): CancelablePromise<T> {
|
|
12
|
+
const source = new CancellationTokenSource();
|
|
13
|
+
|
|
14
|
+
const thenable = callback(source.token);
|
|
15
|
+
const promise = new Promise<T>((resolve, reject) => {
|
|
16
|
+
source.token.onCancellationRequested(() => {
|
|
17
|
+
reject(canceled());
|
|
18
|
+
});
|
|
19
|
+
Promise.resolve(thenable).then(
|
|
20
|
+
(value) => {
|
|
21
|
+
source.dispose();
|
|
22
|
+
resolve(value);
|
|
23
|
+
},
|
|
24
|
+
(err) => {
|
|
25
|
+
source.dispose();
|
|
26
|
+
reject(err);
|
|
27
|
+
},
|
|
28
|
+
);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
return new (class {
|
|
32
|
+
cancel() {
|
|
33
|
+
source.cancel();
|
|
34
|
+
}
|
|
35
|
+
then<TResult1 = T, TResult2 = never>(
|
|
36
|
+
resolve?: ((value: T) => TResult1 | Promise<TResult1>) | undefined | null,
|
|
37
|
+
reject?: ((reason: any) => TResult2 | Promise<TResult2>) | undefined | null,
|
|
38
|
+
): Promise<TResult1 | TResult2> {
|
|
39
|
+
return promise.then(resolve, reject);
|
|
40
|
+
}
|
|
41
|
+
catch<TResult = never>(
|
|
42
|
+
reject?: ((reason: any) => TResult | Promise<TResult>) | undefined | null,
|
|
43
|
+
): Promise<T | TResult> {
|
|
44
|
+
return this.then(undefined, reject);
|
|
45
|
+
}
|
|
46
|
+
finally(onfinally?: (() => void) | undefined | null): Promise<T> {
|
|
47
|
+
return promise.finally(onfinally);
|
|
48
|
+
}
|
|
49
|
+
})() as CancelablePromise<T>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function hookCancellationToken<T>(token: CancellationToken, promise: Promise<T>): PromiseLike<T> {
|
|
53
|
+
return new Promise<T>((resolve, reject) => {
|
|
54
|
+
const sub = token.onCancellationRequested(() => reject(new Error('This promise is cancelled')));
|
|
55
|
+
promise
|
|
56
|
+
.then((value) => {
|
|
57
|
+
sub.dispose();
|
|
58
|
+
resolve(value);
|
|
59
|
+
})
|
|
60
|
+
.catch((err) => {
|
|
61
|
+
sub.dispose();
|
|
62
|
+
reject(err);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export type ITask<T> = () => T;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* A helper to prevent accumulation of sequential async tasks.
|
|
71
|
+
*
|
|
72
|
+
* Imagine a mail man with the sole task of delivering letters. As soon as
|
|
73
|
+
* a letter submitted for delivery, he drives to the destination, delivers it
|
|
74
|
+
* and returns to his base. Imagine that during the trip, N more letters were submitted.
|
|
75
|
+
* When the mail man returns, he picks those N letters and delivers them all in a
|
|
76
|
+
* single trip. Even though N+1 submissions occurred, only 2 deliveries were made.
|
|
77
|
+
*
|
|
78
|
+
* The throttler implements this via the queue() method, by providing it a task
|
|
79
|
+
* factory. Following the example:
|
|
80
|
+
*
|
|
81
|
+
* const throttler = new Throttler();
|
|
82
|
+
* const letters = [];
|
|
83
|
+
*
|
|
84
|
+
* function deliver() {
|
|
85
|
+
* const lettersToDeliver = letters;
|
|
86
|
+
* letters = [];
|
|
87
|
+
* return makeTheTrip(lettersToDeliver);
|
|
88
|
+
* }
|
|
89
|
+
*
|
|
90
|
+
* function onLetterReceived(l) {
|
|
91
|
+
* letters.push(l);
|
|
92
|
+
* throttler.queue(deliver);
|
|
93
|
+
* }
|
|
94
|
+
*/
|
|
95
|
+
export class Throttler {
|
|
96
|
+
private activePromise: Promise<any> | null;
|
|
97
|
+
private queuedPromise: Promise<any> | null;
|
|
98
|
+
private queuedPromiseFactory: ITask<Promise<any>> | null;
|
|
99
|
+
|
|
100
|
+
constructor() {
|
|
101
|
+
this.activePromise = null;
|
|
102
|
+
this.queuedPromise = null;
|
|
103
|
+
this.queuedPromiseFactory = null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
queue<T>(promiseFactory: ITask<Promise<T>>): Promise<T> {
|
|
107
|
+
if (this.activePromise) {
|
|
108
|
+
this.queuedPromiseFactory = promiseFactory;
|
|
109
|
+
|
|
110
|
+
if (!this.queuedPromise) {
|
|
111
|
+
const onComplete = () => {
|
|
112
|
+
this.queuedPromise = null;
|
|
113
|
+
|
|
114
|
+
const result = this.queue(this.queuedPromiseFactory!);
|
|
115
|
+
this.queuedPromiseFactory = null;
|
|
116
|
+
|
|
117
|
+
return result;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
this.queuedPromise = new Promise((c) => {
|
|
121
|
+
this.activePromise && this.activePromise.then(onComplete, onComplete).then(c);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return new Promise((c, e) => {
|
|
126
|
+
this.queuedPromise && this.queuedPromise.then(c, e);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this.activePromise = promiseFactory();
|
|
131
|
+
|
|
132
|
+
return new Promise((c, e) => {
|
|
133
|
+
this.activePromise?.then(
|
|
134
|
+
(result: any) => {
|
|
135
|
+
this.activePromise = null;
|
|
136
|
+
c(result);
|
|
137
|
+
},
|
|
138
|
+
(err: any) => {
|
|
139
|
+
this.activePromise = null;
|
|
140
|
+
e(err);
|
|
141
|
+
},
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export class Sequencer {
|
|
148
|
+
private current: Promise<any> = Promise.resolve(null);
|
|
149
|
+
|
|
150
|
+
queue<T>(promiseTask: ITask<Promise<T>>): Promise<T> {
|
|
151
|
+
return (this.current = this.current.then(() => promiseTask()));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* A helper to delay execution of a task that is being requested often.
|
|
157
|
+
*
|
|
158
|
+
* Following the throttler, now imagine the mail man wants to optimize the number of
|
|
159
|
+
* trips proactively. The trip itself can be long, so he decides not to make the trip
|
|
160
|
+
* as soon as a letter is submitted. Instead he waits a while, in case more
|
|
161
|
+
* letters are submitted. After said waiting period, if no letters were submitted, he
|
|
162
|
+
* decides to make the trip. Imagine that N more letters were submitted after the first
|
|
163
|
+
* one, all within a short period of time between each other. Even though N+1
|
|
164
|
+
* submissions occurred, only 1 delivery was made.
|
|
165
|
+
*
|
|
166
|
+
* The delayer offers this behavior via the trigger() method, into which both the task
|
|
167
|
+
* to be executed and the waiting period (delay) must be passed in as arguments. Following
|
|
168
|
+
* the example:
|
|
169
|
+
*
|
|
170
|
+
* const delayer = new Delayer(WAITING_PERIOD);
|
|
171
|
+
* const letters = [];
|
|
172
|
+
*
|
|
173
|
+
* function letterReceived(l) {
|
|
174
|
+
* letters.push(l);
|
|
175
|
+
* delayer.trigger(() => { return makeTheTrip(); });
|
|
176
|
+
* }
|
|
177
|
+
*/
|
|
178
|
+
export class Delayer<T> implements IDisposable {
|
|
179
|
+
private timeout: any;
|
|
180
|
+
private completionPromise: Promise<any> | null;
|
|
181
|
+
private doResolve: ((value?: any | Promise<any>) => void) | null;
|
|
182
|
+
private doReject?: (err: any) => void;
|
|
183
|
+
private task: ITask<T | Promise<T>> | null;
|
|
184
|
+
|
|
185
|
+
constructor(public defaultDelay: number) {
|
|
186
|
+
this.timeout = null;
|
|
187
|
+
this.completionPromise = null;
|
|
188
|
+
this.doResolve = null;
|
|
189
|
+
this.task = null;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
trigger(task: ITask<T | Promise<T>>, delay: number = this.defaultDelay): Promise<T> {
|
|
193
|
+
this.task = task;
|
|
194
|
+
this.cancelTimeout();
|
|
195
|
+
|
|
196
|
+
if (!this.completionPromise) {
|
|
197
|
+
this.completionPromise = new Promise<void>((c, e) => {
|
|
198
|
+
this.doResolve = c;
|
|
199
|
+
this.doReject = e;
|
|
200
|
+
})
|
|
201
|
+
.then(() => {
|
|
202
|
+
this.completionPromise = null;
|
|
203
|
+
this.doResolve = null;
|
|
204
|
+
const task = this.task;
|
|
205
|
+
this.task = null;
|
|
206
|
+
|
|
207
|
+
return task && task();
|
|
208
|
+
})
|
|
209
|
+
.catch();
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
this.timeout = setTimeout(() => {
|
|
213
|
+
this.timeout = null;
|
|
214
|
+
this.doResolve?.(null);
|
|
215
|
+
}, delay);
|
|
216
|
+
|
|
217
|
+
return this.completionPromise;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
isTriggered(): boolean {
|
|
221
|
+
return this.timeout !== null;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
cancel(): void {
|
|
225
|
+
this.cancelTimeout();
|
|
226
|
+
|
|
227
|
+
if (this.completionPromise) {
|
|
228
|
+
this.doReject && this.doReject(canceled());
|
|
229
|
+
this.completionPromise = null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private cancelTimeout(): void {
|
|
234
|
+
if (this.timeout !== null) {
|
|
235
|
+
clearTimeout(this.timeout);
|
|
236
|
+
this.timeout = null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
dispose(): void {
|
|
241
|
+
this.cancelTimeout();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* A helper to delay execution of a task that is being requested often, while
|
|
247
|
+
* preventing accumulation of consecutive executions, while the task runs.
|
|
248
|
+
*
|
|
249
|
+
* The mail man is clever and waits for a certain amount of time, before going
|
|
250
|
+
* out to deliver letters. While the mail man is going out, more letters arrive
|
|
251
|
+
* and can only be delivered once he is back. Once he is back the mail man will
|
|
252
|
+
* do one more trip to deliver the letters that have accumulated while he was out.
|
|
253
|
+
*/
|
|
254
|
+
export class ThrottledDelayer<T> {
|
|
255
|
+
private delayer: Delayer<Promise<T>>;
|
|
256
|
+
private throttler: Throttler;
|
|
257
|
+
|
|
258
|
+
constructor(defaultDelay: number) {
|
|
259
|
+
this.delayer = new Delayer(defaultDelay);
|
|
260
|
+
this.throttler = new Throttler();
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
trigger(promiseFactory: ITask<Promise<T>>, delay?: number): Promise<T> {
|
|
264
|
+
return this.delayer.trigger(() => this.throttler.queue(promiseFactory), delay) as any as Promise<T>;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
isTriggered(): boolean {
|
|
268
|
+
return this.delayer.isTriggered();
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
cancel(): void {
|
|
272
|
+
this.delayer.cancel();
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
dispose(): void {
|
|
276
|
+
this.delayer.dispose();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* A barrier that is initially closed and then becomes opened permanently.
|
|
282
|
+
*/
|
|
283
|
+
export class Barrier {
|
|
284
|
+
private _isOpen: boolean;
|
|
285
|
+
private _promise: Promise<boolean>;
|
|
286
|
+
private _completePromise!: (v: boolean) => void;
|
|
287
|
+
|
|
288
|
+
constructor() {
|
|
289
|
+
this._isOpen = false;
|
|
290
|
+
this._promise = new Promise<boolean>((c) => {
|
|
291
|
+
this._completePromise = c;
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
isOpen(): boolean {
|
|
296
|
+
return this._isOpen;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
open(): void {
|
|
300
|
+
this._isOpen = true;
|
|
301
|
+
this._completePromise(true);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
wait(): Promise<boolean> {
|
|
305
|
+
return this._promise;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* A barrier that is initially closed and then becomes opened permanently after a certain period of
|
|
311
|
+
* time or when open is called explicitly
|
|
312
|
+
*/
|
|
313
|
+
export class AutoOpenBarrier extends Barrier {
|
|
314
|
+
private readonly _timeout: any;
|
|
315
|
+
|
|
316
|
+
constructor(autoOpenTimeMs: number) {
|
|
317
|
+
super();
|
|
318
|
+
this._timeout = setTimeout(() => this.open(), autoOpenTimeMs);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
override open(): void {
|
|
322
|
+
clearTimeout(this._timeout);
|
|
323
|
+
super.open();
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export function isThenable<T>(obj: any): obj is Promise<T> {
|
|
328
|
+
return obj && typeof (obj as Promise<any>).then === 'function';
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
export function raceTimeout<T>(promise: Promise<T>, timeout: number, onTimeout?: () => void): Promise<T | undefined> {
|
|
332
|
+
let promiseResolve: ((value: T | undefined) => void) | undefined;
|
|
333
|
+
|
|
334
|
+
const timer = setTimeout(() => {
|
|
335
|
+
promiseResolve?.(undefined);
|
|
336
|
+
onTimeout?.();
|
|
337
|
+
}, timeout);
|
|
338
|
+
|
|
339
|
+
return Promise.race([
|
|
340
|
+
promise.finally(() => clearTimeout(timer)),
|
|
341
|
+
new Promise<T | undefined>((resolve) => (promiseResolve = resolve)),
|
|
342
|
+
]);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
export function asPromise<T>(callback: () => T | Thenable<T>): Promise<T> {
|
|
346
|
+
return new Promise<T>((resolve, reject) => {
|
|
347
|
+
const item = callback();
|
|
348
|
+
if (isThenable<T>(item)) {
|
|
349
|
+
item.then(resolve, reject);
|
|
350
|
+
} else {
|
|
351
|
+
resolve(item);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// #region -- run on idle tricks ------------
|
|
357
|
+
|
|
358
|
+
export interface IdleDeadline {
|
|
359
|
+
readonly didTimeout: boolean;
|
|
360
|
+
timeRemaining(): DOMHighResTimeStamp;
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Execute the callback the next time the browser is idle
|
|
364
|
+
*/
|
|
365
|
+
export let runWhenIdle: (callback: (idle: IdleDeadline) => void, timeout?: number) => IDisposable;
|
|
366
|
+
|
|
367
|
+
declare function requestIdleCallback(callback: (args: IdleDeadline) => void, options?: { timeout: number }): number;
|
|
368
|
+
declare function cancelIdleCallback(handle: number): void;
|
|
369
|
+
|
|
370
|
+
(function () {
|
|
371
|
+
if (typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function') {
|
|
372
|
+
const dummyIdle: IdleDeadline = Object.freeze({
|
|
373
|
+
didTimeout: true,
|
|
374
|
+
timeRemaining() {
|
|
375
|
+
return 15;
|
|
376
|
+
},
|
|
377
|
+
});
|
|
378
|
+
runWhenIdle = (runner) => {
|
|
379
|
+
const handle = setTimeout(() => runner(dummyIdle));
|
|
380
|
+
let disposed = false;
|
|
381
|
+
return {
|
|
382
|
+
dispose() {
|
|
383
|
+
if (disposed) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
disposed = true;
|
|
387
|
+
clearTimeout(handle);
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
};
|
|
391
|
+
} else {
|
|
392
|
+
runWhenIdle = (runner, timeout?) => {
|
|
393
|
+
const handle: number = requestIdleCallback(runner, typeof timeout === 'number' ? { timeout } : undefined);
|
|
394
|
+
let disposed = false;
|
|
395
|
+
return {
|
|
396
|
+
dispose() {
|
|
397
|
+
if (disposed) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
disposed = true;
|
|
401
|
+
cancelIdleCallback(handle);
|
|
402
|
+
},
|
|
403
|
+
};
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
})();
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* An implementation of the "idle-until-urgent"-strategy as introduced
|
|
410
|
+
* here: https://philipwalton.com/articles/idle-until-urgent/
|
|
411
|
+
*/
|
|
412
|
+
export class IdleValue<T> {
|
|
413
|
+
private readonly _executor: () => void;
|
|
414
|
+
private readonly _handle: IDisposable;
|
|
415
|
+
|
|
416
|
+
private _didRun = false;
|
|
417
|
+
private _value?: T;
|
|
418
|
+
private _error: any;
|
|
419
|
+
|
|
420
|
+
constructor(executor: () => T) {
|
|
421
|
+
this._executor = () => {
|
|
422
|
+
try {
|
|
423
|
+
this._value = executor();
|
|
424
|
+
} catch (err) {
|
|
425
|
+
this._error = err;
|
|
426
|
+
} finally {
|
|
427
|
+
this._didRun = true;
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
this._handle = runWhenIdle(() => this._executor());
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
dispose(): void {
|
|
434
|
+
this._handle.dispose();
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
getValue(): T {
|
|
438
|
+
if (!this._didRun) {
|
|
439
|
+
this._handle.dispose();
|
|
440
|
+
this._executor();
|
|
441
|
+
}
|
|
442
|
+
if (this._error) {
|
|
443
|
+
throw this._error;
|
|
444
|
+
}
|
|
445
|
+
return this._value as T;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export type Mutable<T> = { -readonly [P in keyof T]: T[P] };
|
|
450
|
+
|
|
451
|
+
export function first<T>(
|
|
452
|
+
promiseFactories: ITask<Promise<T>>[],
|
|
453
|
+
shouldStop: (t: T) => boolean = (t) => !!t,
|
|
454
|
+
defaultValue: T | null = null,
|
|
455
|
+
): Promise<T | null> {
|
|
456
|
+
let index = 0;
|
|
457
|
+
const len = promiseFactories.length;
|
|
458
|
+
|
|
459
|
+
const loop: () => Promise<T | null> = () => {
|
|
460
|
+
if (index >= len) {
|
|
461
|
+
return Promise.resolve(defaultValue);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
const factory = promiseFactories[index++];
|
|
465
|
+
const promise = Promise.resolve(factory());
|
|
466
|
+
|
|
467
|
+
return promise.then((result) => {
|
|
468
|
+
if (shouldStop(result)) {
|
|
469
|
+
return Promise.resolve(result);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return loop();
|
|
473
|
+
});
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
return loop();
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
export function timeout(millis: number): CancelablePromise<void>;
|
|
480
|
+
export function timeout(millis: number, token: CancellationToken): Promise<void>;
|
|
481
|
+
export function timeout(millis: number, token?: CancellationToken): CancelablePromise<void> | Promise<void> {
|
|
482
|
+
if (!token) {
|
|
483
|
+
return createCancelablePromise((token) => timeout(millis, token));
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
return new Promise((resolve, reject) => {
|
|
487
|
+
const handle = setTimeout(resolve, millis);
|
|
488
|
+
token.onCancellationRequested(() => {
|
|
489
|
+
clearTimeout(handle);
|
|
490
|
+
reject(canceled());
|
|
491
|
+
});
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export function raceCancellation<T>(promise: Promise<T>, token: CancellationToken): Promise<T | undefined>;
|
|
496
|
+
export function raceCancellation<T>(promise: Promise<T>, token: CancellationToken, defaultValue: T): Promise<T>;
|
|
497
|
+
export function raceCancellation<T>(
|
|
498
|
+
promise: Promise<T>,
|
|
499
|
+
token: CancellationToken,
|
|
500
|
+
defaultValue?: T,
|
|
501
|
+
): Promise<T | undefined> {
|
|
502
|
+
return Promise.race([
|
|
503
|
+
promise,
|
|
504
|
+
new Promise<T | undefined>((resolve) => token.onCancellationRequested(() => resolve(defaultValue))),
|
|
505
|
+
]);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export class RunOnceScheduler {
|
|
509
|
+
protected runner: ((...args: unknown[]) => void) | null;
|
|
510
|
+
|
|
511
|
+
private timeoutToken: any;
|
|
512
|
+
private timeout: number;
|
|
513
|
+
private timeoutHandler: () => void;
|
|
514
|
+
|
|
515
|
+
constructor(runner: (...args: any[]) => void, delay: number) {
|
|
516
|
+
this.timeoutToken = -1;
|
|
517
|
+
this.runner = runner;
|
|
518
|
+
this.timeout = delay;
|
|
519
|
+
this.timeoutHandler = this.onTimeout.bind(this);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/**
|
|
523
|
+
* Dispose RunOnceScheduler
|
|
524
|
+
*/
|
|
525
|
+
dispose(): void {
|
|
526
|
+
this.cancel();
|
|
527
|
+
this.runner = null;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Cancel current scheduled runner (if any).
|
|
532
|
+
*/
|
|
533
|
+
cancel(): void {
|
|
534
|
+
if (this.isScheduled()) {
|
|
535
|
+
clearTimeout(this.timeoutToken);
|
|
536
|
+
this.timeoutToken = -1;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/**
|
|
541
|
+
* Cancel previous runner (if any) & schedule a new runner.
|
|
542
|
+
*/
|
|
543
|
+
schedule(delay = this.timeout): void {
|
|
544
|
+
this.cancel();
|
|
545
|
+
this.timeoutToken = setTimeout(this.timeoutHandler, delay);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
get delay(): number {
|
|
549
|
+
return this.timeout;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
set delay(value: number) {
|
|
553
|
+
this.timeout = value;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
/**
|
|
557
|
+
* Returns true if scheduled.
|
|
558
|
+
*/
|
|
559
|
+
isScheduled(): boolean {
|
|
560
|
+
return this.timeoutToken !== -1;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
private onTimeout() {
|
|
564
|
+
this.timeoutToken = -1;
|
|
565
|
+
if (this.runner) {
|
|
566
|
+
this.doRun();
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
protected doRun(): void {
|
|
571
|
+
if (this.runner) {
|
|
572
|
+
this.runner();
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export function disposableTimeout(handler: () => void, timeout = 0): IDisposable {
|
|
578
|
+
const timer = setTimeout(handler, timeout);
|
|
579
|
+
return toDisposable(() => clearTimeout(timer));
|
|
580
|
+
}
|