import { CancellationToken , CancellationTokenSource } from './cancellation' ; import * as errors from './errors' ; import { Emitter , Event } from './event' ; import { Disposable , IDisposable , toDisposable } from './lifecycle' ; import { URI } from './uri' ; interface Thenable < T > { then < U > ( onFulfilled ? , onRejected ? ) : Thenable < U > ; then < U > ( onFulfilled ? , onRejected ? ) : Thenable < U > ; } export function isThenable < T > ( obj ) { return obj && typeof ( < Promise < any > > obj ) . then === 'function' ; } export interface CancelablePromise < T > extends Promise < T > { cancel ( ) : void ; } export function createCancelablePromise < T > ( callback ) { const source = new CancellationTokenSource ( ) ; const thenable = callback ( source . token ) ; const promise = new Promise < T > ( ( resolve , reject ) => { source . token . onCancellationRequested ( ( ) => { reject ( errors . canceled ( ) ) ; } ) ; Promise . resolve ( thenable ) . then ( ( value ) => { source . dispose ( ) ; resolve ( value ) ; } , ( err ) => { source . dispose ( ) ; reject ( err ) ; } ) ; } ) ; return new ( class implements CancelablePromise < T > { [ Symbol . toStringTag ] : string ; cancel ( ) { source . cancel ( ) ; } then < TResult1 = T , TResult2 = never > ( resolve ? , reject ? ) { return promise . then ( resolve , reject ) ; } catch < TResult = never > ( reject ? ) { return this . then ( undefined , reject ) ; } finally ( onfinally ? ) { return promise . finally ( onfinally ) ; } } ) ( ) ; } export function asPromise < T > ( callback ) { return new Promise < T > ( ( resolve , reject ) => { let item = callback ( ) ; if ( isThenable < T > ( item ) ) { item . then ( resolve , reject ) ; } else { resolve ( item ) ; } } ) ; } export interface ITask < T > { ( ) : T ; } /**
 * A helper to prevent accumulation of sequential async tasks.
 *
 * Imagine a mail man with the sole task of delivering letters. As soon as
 * a letter submitted for delivery, he drives to the destination, delivers it
 * and returns to his base. Imagine that during the trip, N more letters were submitted.
 * When the mail man returns, he picks those N letters and delivers them all in a
 * single trip. Even though N+1 submissions occurred, only 2 deliveries were made.
 *
 * The throttler implements this via the queue() method, by providing it a task
 * factory. Following the example:
 *
 * 		const throttler = new Throttler();
 * 		const letters = [];
 *
 * 		function deliver() {
 * 			const lettersToDeliver = letters;
 * 			letters = [];
 * 			return makeTheTrip(lettersToDeliver);
 * 		}
 *
 * 		function onLetterReceived(l) {
 * 			letters.push(l);
 * 			throttler.queue(deliver);
 * 		}
 */ export class Throttler { private activePromise : Promise < any > | null ; private queuedPromise : Promise < any > | null ; private queuedPromiseFactory : ITask < Promise < any > > | null ; constructor ( ) { this . activePromise = null ; this . queuedPromise = null ; this . queuedPromiseFactory = null ; } queue < T > ( promiseFactory ) { if ( this . activePromise ) { this . queuedPromiseFactory = promiseFactory ; if ( ! this . queuedPromise ) { const onComplete = ( ) => { this . queuedPromise = null ; const result = this . queue ( this . queuedPromiseFactory ! ) ; this . queuedPromiseFactory = null ; return result ; } ; this . queuedPromise = new Promise ( ( c ) => { this . activePromise ! . then ( onComplete , onComplete ) . then ( c ) ; } ) ; } return new Promise ( ( c , e ) => { this . queuedPromise ! . then ( c , e ) ; } ) ; } this . activePromise = promiseFactory ( ) ; return new Promise ( ( c , e ) => { this . activePromise ! . then ( ( result ) => { this . activePromise = null ; c ( result ) ; } , ( err ) => { this . activePromise = null ; e ( err ) ; } ) ; } ) ; } } export class Sequencer { private current : Promise < any > = Promise . resolve ( null ) ; queue < T > ( promiseTask ) { return ( this . current = this . current . then ( ( ) => promiseTask ( ) ) ) ; } } /**
 * A helper to delay execution of a task that is being requested often.
 *
 * Following the throttler, now imagine the mail man wants to optimize the number of
 * trips proactively. The trip itself can be long, so he decides not to make the trip
 * as soon as a letter is submitted. Instead he waits a while, in case more
 * letters are submitted. After said waiting period, if no letters were submitted, he
 * decides to make the trip. Imagine that N more letters were submitted after the first
 * one, all within a short period of time between each other. Even though N+1
 * submissions occurred, only 1 delivery was made.
 *
 * The delayer offers this behavior via the trigger() method, into which both the task
 * to be executed and the waiting period (delay) must be passed in as arguments. Following
 * the example:
 *
 * 		const delayer = new Delayer(WAITING_PERIOD);
 * 		const letters = [];
 *
 * 		function letterReceived(l) {
 * 			letters.push(l);
 * 			delayer.trigger(() => { return makeTheTrip(); });
 * 		}
 */ export class Delayer < T > implements IDisposable { private timeout : any ; private completionPromise : Promise < any > | null ; private doResolve : ( ( value ? : any | Promise < any > ) => void ) | null ; private doReject ! : ( err : any ) => void ; private task : ITask < T | Promise < T > > | null ; constructor ( public defaultDelay ) { this . timeout = null ; this . completionPromise = null ; this . doResolve = null ; this . task = null ; } trigger ( task , delay = this . defaultDelay ) { this . task = task ; this . cancelTimeout ( ) ; if ( ! this . completionPromise ) { this . completionPromise = new Promise ( ( c , e ) => { this . doResolve = c ; this . doReject = e ; } ) . then ( ( ) => { this . completionPromise = null ; this . doResolve = null ; const task = this . task ! ; this . task = null ; return task ( ) ; } ) ; } this . timeout = setTimeout ( ( ) => { this . timeout = null ; this . doResolve ! ( null ) ; } , delay ) ; return this . completionPromise ; } isTriggered ( ) { return this . timeout !== null ; } cancel ( ) { this . cancelTimeout ( ) ; if ( this . completionPromise ) { this . doReject ( errors . canceled ( ) ) ; this . completionPromise = null ; } } private cancelTimeout ( ) { if ( this . timeout !== null ) { clearTimeout ( this . timeout ) ; this . timeout = null ; } } dispose ( ) { this . cancelTimeout ( ) ; } } /**
 * A helper to delay execution of a task that is being requested often, while
 * preventing accumulation of consecutive executions, while the task runs.
 *
 * The mail man is clever and waits for a certain amount of time, before going
 * out to deliver letters. While the mail man is going out, more letters arrive
 * and can only be delivered once he is back. Once he is back the mail man will
 * do one more trip to deliver the letters that have accumulated while he was out.
 */ export class ThrottledDelayer < T > { private delayer : Delayer < Promise < T > > ; private throttler : Throttler ; constructor ( defaultDelay ) { this . delayer = new Delayer ( defaultDelay ) ; this . throttler = new Throttler ( ) ; } trigger ( promiseFactory , delay ? ) { return this . delayer . trigger ( ( ) => this . throttler . queue ( promiseFactory ) , delay ) as any as Promise < T > ; } isTriggered ( ) { return this . delayer . isTriggered ( ) ; } cancel ( ) { this . delayer . cancel ( ) ; } dispose ( ) { this . delayer . dispose ( ) ; } } /**
 * A barrier that is initially closed and then becomes opened permanently.
 */ export class Barrier { private _isOpen : boolean ; private _promise : Promise < boolean > ; private _completePromise ! : ( v : boolean ) => void ; constructor ( ) { this . _isOpen = false ; this . _promise = new Promise < boolean > ( ( c , e ) => { this . _completePromise = c ; } ) ; } isOpen ( ) { return this . _isOpen ; } open ( ) { this . _isOpen = true ; this . _completePromise ( true ) ; } wait ( ) { return this . _promise ; } } export function timeout ( millis ) ; export function timeout ( millis , token ) ; export function timeout ( millis , token ? ) { if ( ! token ) { return createCancelablePromise ( ( token ) => timeout ( millis , token ) ) ; } return new Promise ( ( resolve , reject ) => { const handle = setTimeout ( resolve , millis ) ; token . onCancellationRequested ( ( ) => { clearTimeout ( handle ) ; reject ( errors . canceled ( ) ) ; } ) ; } ) ; } export function disposableTimeout ( handler , timeout = 0 ) { const timer = setTimeout ( handler , timeout ) ; return toDisposable ( ( ) => clearTimeout ( timer ) ) ; } export function ignoreErrors < T > ( promise ) { return promise . then ( undefined , ( _ ) => undefined ) ; } /**
 * Runs the provided list of promise factories in sequential order. The returned
 * promise will complete to an array of results from each promise.
 */ export function sequence < T > ( promiseFactories ) { const results = [ ] ; let index = 0 ; const len = promiseFactories . length ; function next ( ) { return index < len ? promiseFactories [ index ++ ] ( ) : null ; } function thenHandler ( result ) { if ( result !== undefined && result !== null ) { results . push ( result ) ; } const n = next ( ) ; if ( n ) { return n . then ( thenHandler ) ; } return Promise . resolve ( results ) ; } return Promise . resolve ( null ) . then ( thenHandler ) ; } export function first < T > ( promiseFactories , shouldStop = ( t ) => ! ! t , defaultValue = null ) { let index = 0 ; const len = promiseFactories . length ; const loop = ( ) => { if ( index >= len ) { return Promise . resolve ( defaultValue ) ; } const factory = promiseFactories [ index ++ ] ; const promise = Promise . resolve ( factory ( ) ) ; return promise . then ( ( result ) => { if ( shouldStop ( result ) ) { return Promise . resolve ( result ) ; } return loop ( ) ; } ) ; } ; return loop ( ) ; } interface ILimitedTaskFactory < T > { factory : ITask < Promise < T > > ; c : ( value ? : T | Promise < T > ) => void ; e : ( error ? : any ) => void ; } /**
 * A helper to queue N promises and run them all with a max degree of parallelism. The helper
 * ensures that at any time no more than M promises are running at the same time.
 */ export class Limiter < T > { private _size = 0 ; private runningPromises : number ; private maxDegreeOfParalellism : number ; private outstandingPromises : ILimitedTaskFactory < T > [ ] ; private readonly _onFinished : Emitter < void > ; constructor ( maxDegreeOfParalellism ) { this . maxDegreeOfParalellism = maxDegreeOfParalellism ; this . outstandingPromises = [ ] ; this . runningPromises = 0 ; this . _onFinished = new Emitter < void > ( ) ; } public get onFinished ( ) : Event < void > { return this . _onFinished . event ; } public get size ( ) : number { return this . _size ; } queue ( factory ) { this . _size ++ ; return new Promise < T > ( ( c , e ) => { this . outstandingPromises . push ( { factory , c : c as any , e } ) ; this . consume ( ) ; } ) ; } private consume ( ) { while ( this . outstandingPromises . length && this . runningPromises < this . maxDegreeOfParalellism ) { const iLimitedTask = this . outstandingPromises . shift ( ) ! ; this . runningPromises ++ ; const promise = iLimitedTask . factory ( ) ; promise . then ( iLimitedTask . c , iLimitedTask . e ) ; promise . then ( ( ) => this . consumed ( ) , ( ) => this . consumed ( ) ) ; } } private consumed ( ) { this . _size -- ; this . runningPromises -- ; if ( this . outstandingPromises . length > 0 ) { this . consume ( ) ; } else { this . _onFinished . fire ( ) ; } } public dispose ( ) { this . _onFinished . dispose ( ) ; } } /**
 * A queue is handles one promise at a time and guarantees that at any time only one promise is executing.
 */ export class Queue < T > extends Limiter < T > { constructor ( ) { super ( 1 ) ; } } /**
 * A helper to organize queues per resource. The ResourceQueue makes sure to manage queues per resource
 * by disposing them once the queue is empty.
 */ export class ResourceQueue { private queues : { [ path ] : Queue < void > ; } ; constructor ( ) { this . queues = Object . create ( null ) ; } public queueFor ( resource ) { const key = resource . toString ( ) ; if ( ! this . queues [ key ] ) { const queue = new Queue < void > ( ) ; queue . onFinished ( ( ) => { queue . dispose ( ) ; delete this . queues [ key ] ; } ) ; this . queues [ key ] = queue ; } return this . queues [ key ] ; } } export class TimeoutTimer extends Disposable { private _token : any ; constructor ( ) ; constructor ( runner , timeout ) ; constructor ( runner ? , timeout ? ) { super ( ) ; this . _token = - 1 ; if ( typeof runner === 'function' && typeof timeout === 'number' ) { this . setIfNotSet ( runner , timeout ) ; } } dispose ( ) { this . cancel ( ) ; super . dispose ( ) ; } cancel ( ) { if ( this . _token !== - 1 ) { clearTimeout ( this . _token ) ; this . _token = - 1 ; } } cancelAndSet ( runner , timeout ) { this . cancel ( ) ; this . _token = setTimeout ( ( ) => { this . _token = - 1 ; runner ( ) ; } , timeout ) ; } setIfNotSet ( runner , timeout ) { if ( this . _token !== - 1 ) { return ; } this . _token = setTimeout ( ( ) => { this . _token = - 1 ; runner ( ) ; } , timeout ) ; } } export class IntervalTimer extends Disposable { private _token : any ; constructor ( ) { super ( ) ; this . _token = - 1 ; } dispose ( ) { this . cancel ( ) ; super . dispose ( ) ; } cancel ( ) { if ( this . _token !== - 1 ) { clearInterval ( this . _token ) ; this . _token = - 1 ; } } cancelAndSet ( runner , interval ) { this . cancel ( ) ; this . _token = setInterval ( ( ) => { runner ( ) ; } , interval ) ; } } export class RunOnceScheduler { protected runner : ( ( ... args : any [ ] ) => void ) | null ; private timeoutToken : any ; private timeout : number ; private timeoutHandler : ( ) => void ; constructor ( runner , timeout ) { this . timeoutToken = - 1 ; this . runner = runner ; this . timeout = timeout ; this . timeoutHandler = this . onTimeout . bind ( this ) ; } /**
     * Dispose RunOnceScheduler
     */ dispose ( ) { this . cancel ( ) ; this . runner = null ; } /**
     * Cancel current scheduled runner (if any).
     */ cancel ( ) { if ( this . isScheduled ( ) ) { clearTimeout ( this . timeoutToken ) ; this . timeoutToken = - 1 ; } } /**
     * Cancel previous runner (if any) & schedule a new runner.
     */ schedule ( delay = this . timeout ) { this . cancel ( ) ; this . timeoutToken = setTimeout ( this . timeoutHandler , delay ) ; } /**
     * Returns true if scheduled.
     */ isScheduled ( ) { return this . timeoutToken !== - 1 ; } private onTimeout ( ) { this . timeoutToken = - 1 ; if ( this . runner ) { this . doRun ( ) ; } } protected doRun ( ) { if ( this . runner ) { this . runner ( ) ; } } } export class RunOnceWorker < T > extends RunOnceScheduler { private units : T [ ] = [ ] ; constructor ( runner , timeout ) { super ( runner , timeout ) ; } work ( unit ) { this . units . push ( unit ) ; if ( ! this . isScheduled ( ) ) { this . schedule ( ) ; } } protected doRun ( ) { const units = this . units ; this . units = [ ] ; if ( this . runner ) { this . runner ( units ) ; } } dispose ( ) { this . units = [ ] ; super . dispose ( ) ; } } export function nfcall ( fn , ... args ) ; export function nfcall < T > ( fn , ... args ) ; export function nfcall ( fn , ... args ) { return new Promise ( ( c , e ) => fn ( ... args , ( err , result ) => ( err ? e ( err ) : c ( result ) ) ) ) ; } export function ninvoke ( thisArg , fn , ... args ) ; export function ninvoke < T > ( thisArg , fn , ... args ) ; export function ninvoke ( thisArg , fn , ... args ) { return new Promise ( ( resolve , reject ) => fn . call ( thisArg , ... args , ( err , result ) => ( err ? reject ( err ) : resolve ( result ) ) ) ) ; } export interface IdleDeadline { readonly didTimeout : boolean ; timeRemaining ( ) : DOMHighResTimeStamp ; } /**
 * Execute the callback the next time the browser is idle
 */ export let runWhenIdle ; declare function requestIdleCallback ( callback , options ? ) ; declare function cancelIdleCallback ( handle ) ; ( function ( ) { if ( typeof requestIdleCallback !== 'function' || typeof cancelIdleCallback !== 'function' ) { let dummyIdle = Object . freeze ( { didTimeout : true , timeRemaining ( ) { return 15 ; } , } ) ; runWhenIdle = ( runner ) => { let handle = setTimeout ( ( ) => runner ( dummyIdle ) ) ; let disposed = false ; return { dispose ( ) { if ( disposed ) { return ; } disposed = true ; clearTimeout ( handle ) ; } , } ; } ; } else { runWhenIdle = ( runner , timeout ? ) => { let handle = requestIdleCallback ( runner , typeof timeout === 'number' ? { timeout } : undefined ) ; let disposed = false ; return { dispose ( ) { if ( disposed ) { return ; } disposed = true ; cancelIdleCallback ( handle ) ; } , } ; } ; } } ) ( ) ; /**
 * An implementation of the "idle-until-urgent"-strategy as introduced
 * here: https://philipwalton.com/articles/idle-until-urgent/
 */ export class IdleValue < T > { private readonly _executor : ( ) => void ; private readonly _handle : IDisposable ; private _didRun ! : boolean ; private _value ! : T ; private _error : any ; constructor ( executor ) { this . _executor = ( ) => { try { this . _value = executor ( ) ; } catch ( err ) { this . _error = err ; } finally { this . _didRun = true ; } } ; this . _handle = runWhenIdle ( ( ) => this . _executor ( ) ) ; } dispose ( ) { this . _handle . dispose ( ) ; } getValue ( ) { if ( ! this . _didRun ) { this . _handle . dispose ( ) ; this . _executor ( ) ; } if ( this . _error ) { throw this . _error ; } return this . _value ; } }