@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.
Files changed (114) hide show
  1. package/lib/arrays.d.ts +3 -3
  2. package/lib/arrays.d.ts.map +1 -1
  3. package/lib/arrays.js.map +1 -1
  4. package/lib/async.d.ts +3 -3
  5. package/lib/async.d.ts.map +1 -1
  6. package/lib/buffer.js +4 -4
  7. package/lib/buffer.js.map +1 -1
  8. package/lib/character-classifier.js +3 -3
  9. package/lib/character-classifier.js.map +1 -1
  10. package/lib/decorators.d.ts +1 -1
  11. package/lib/decorators.d.ts.map +1 -1
  12. package/lib/encoding.d.ts +7 -1
  13. package/lib/encoding.d.ts.map +1 -1
  14. package/lib/encoding.js +15 -2
  15. package/lib/encoding.js.map +1 -1
  16. package/lib/errors.d.ts +2 -2
  17. package/lib/errors.d.ts.map +1 -1
  18. package/lib/event.d.ts +2 -2
  19. package/lib/event.d.ts.map +1 -1
  20. package/lib/filters.d.ts +3 -3
  21. package/lib/filters.d.ts.map +1 -1
  22. package/lib/filters.js +25 -25
  23. package/lib/filters.js.map +1 -1
  24. package/lib/glob.d.ts +2 -2
  25. package/lib/glob.d.ts.map +1 -1
  26. package/lib/glob.js +1 -1
  27. package/lib/glob.js.map +1 -1
  28. package/lib/hash.js +10 -10
  29. package/lib/hash.js.map +1 -1
  30. package/lib/iterator.d.ts +1 -1
  31. package/lib/iterator.d.ts.map +1 -1
  32. package/lib/linked-text.d.ts +1 -1
  33. package/lib/linked-text.d.ts.map +1 -1
  34. package/lib/linked-text.js.map +1 -1
  35. package/lib/map.js +17 -17
  36. package/lib/map.js.map +1 -1
  37. package/lib/objects.d.ts +1 -0
  38. package/lib/objects.d.ts.map +1 -1
  39. package/lib/objects.js +38 -1
  40. package/lib/objects.js.map +1 -1
  41. package/lib/os.d.ts +1 -8
  42. package/lib/os.d.ts.map +1 -1
  43. package/lib/os.js +4 -8
  44. package/lib/os.js.map +1 -1
  45. package/lib/path.d.ts +1 -1
  46. package/lib/path.d.ts.map +1 -1
  47. package/lib/path.js +29 -29
  48. package/lib/path.js.map +1 -1
  49. package/lib/platform.js +8 -8
  50. package/lib/platform.js.map +1 -1
  51. package/lib/process.d.ts.map +1 -1
  52. package/lib/process.js +28 -13
  53. package/lib/process.js.map +1 -1
  54. package/lib/progress.js +3 -3
  55. package/lib/progress.js.map +1 -1
  56. package/lib/strings.js +9 -9
  57. package/lib/strings.js.map +1 -1
  58. package/lib/types.d.ts +5 -1
  59. package/lib/types.d.ts.map +1 -1
  60. package/lib/types.js +8 -1
  61. package/lib/types.js.map +1 -1
  62. package/lib/uint.js +4 -4
  63. package/lib/uint.js.map +1 -1
  64. package/lib/uri.js +8 -8
  65. package/lib/uri.js.map +1 -1
  66. package/lib/uuid.d.ts +1 -1
  67. package/lib/uuid.d.ts.map +1 -1
  68. package/lib/uuid.js +3 -2
  69. package/lib/uuid.js.map +1 -1
  70. package/package.json +8 -6
  71. package/src/ansi.ts +10 -0
  72. package/src/argv.ts +57 -0
  73. package/src/arrays.ts +328 -0
  74. package/src/async.ts +580 -0
  75. package/src/buffer.ts +290 -0
  76. package/src/cache.ts +37 -0
  77. package/src/cancellation.ts +136 -0
  78. package/src/charCode.ts +425 -0
  79. package/src/character-classifier.ts +82 -0
  80. package/src/const/encoding.ts +242 -0
  81. package/src/const/index.ts +1 -0
  82. package/src/date.ts +36 -0
  83. package/src/decorators.ts +166 -0
  84. package/src/disposable.ts +377 -0
  85. package/src/encoding.ts +278 -0
  86. package/src/errors.ts +192 -0
  87. package/src/event.ts +1024 -0
  88. package/src/file-uri.ts +41 -0
  89. package/src/filters.ts +887 -0
  90. package/src/functional.ts +43 -0
  91. package/src/glob.ts +752 -0
  92. package/src/hash.ts +336 -0
  93. package/src/iconLabels.ts +149 -0
  94. package/src/index.ts +40 -0
  95. package/src/iterator.ts +36 -0
  96. package/src/lifecycle.ts +48 -0
  97. package/src/linked-list.ts +144 -0
  98. package/src/linked-text.ts +55 -0
  99. package/src/lru-map.ts +133 -0
  100. package/src/map.ts +934 -0
  101. package/src/marshalling.ts +62 -0
  102. package/src/objects.ts +145 -0
  103. package/src/os.ts +76 -0
  104. package/src/path.ts +1885 -0
  105. package/src/platform.ts +194 -0
  106. package/src/process.ts +43 -0
  107. package/src/progress.ts +83 -0
  108. package/src/promises.ts +23 -0
  109. package/src/sequence.ts +28 -0
  110. package/src/strings.ts +1002 -0
  111. package/src/types.ts +214 -0
  112. package/src/uint.ts +59 -0
  113. package/src/uri.ts +298 -0
  114. 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
+ }