diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index d866111a8222d..b4ea178ba8fa6 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -179,6 +179,17 @@ export function fromPromise(promise: TPromise>): Event { return emitter.event; } +export function once(event: Event): Event { + return (listener, thisArgs = null, disposables?) => { + const result = event(e => { + result.dispose(); + return listener.call(thisArgs, e); + }, null, disposables); + + return result; + }; +} + export function mapEvent(event: Event, map: (i:I)=>O): Event { return (listener, thisArgs = null, disposables?) => event(i => listener.call(thisArgs, map(i)), null, disposables); } diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 416005e8bc42d..d79acb3fda066 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -5,7 +5,7 @@ 'use strict'; import * as assert from 'assert'; -import Event, {Emitter, fromEventEmitter, debounceEvent, EventBufferer} from 'vs/base/common/event'; +import Event, {Emitter, fromEventEmitter, debounceEvent, EventBufferer, once} from 'vs/base/common/event'; import {IDisposable} from 'vs/base/common/lifecycle'; import {EventEmitter} from 'vs/base/common/eventEmitter'; import Errors = require('vs/base/common/errors'); @@ -254,4 +254,32 @@ suite('EventBufferer', () => { listener.dispose(); }); + + test('once', () => { + const emitter = new Emitter(); + + let counter1 = 0, counter2 = 0, counter3 = 0; + + const listener1 = emitter.event(() => counter1++); + const listener2 = once(emitter.event)(() => counter2++); + const listener3 = once(emitter.event)(() => counter3++); + + assert.equal(counter1, 0); + assert.equal(counter2, 0); + assert.equal(counter3, 0); + + listener3.dispose(); + emitter.fire(); + assert.equal(counter1, 1); + assert.equal(counter2, 1); + assert.equal(counter3, 0); + + emitter.fire(); + assert.equal(counter1, 2); + assert.equal(counter2, 1); + assert.equal(counter3, 0); + + listener1.dispose(); + listener2.dispose(); + }); }); \ No newline at end of file