mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 20:13:32 +01:00
Revert "allow to reuse the same function/context when listening to events"
This reverts commit 7cb8ac43e6.
This commit is contained in:
@@ -6,21 +6,47 @@
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
|
||||
export default class CallbackList {
|
||||
|
||||
private _callbacks: LinkedList<[Function, any]>;
|
||||
private _callbacks: Function[];
|
||||
private _contexts: any[];
|
||||
|
||||
public add(callback: Function, context: any = null, bucket?: IDisposable[]): () => void {
|
||||
public add(callback: Function, context: any = null, bucket?: IDisposable[]): void {
|
||||
if (!this._callbacks) {
|
||||
this._callbacks = new LinkedList<[Function, any]>();
|
||||
this._callbacks = [];
|
||||
this._contexts = [];
|
||||
}
|
||||
const remove = this._callbacks.insert([callback, context]);
|
||||
this._callbacks.push(callback);
|
||||
this._contexts.push(context);
|
||||
|
||||
if (Array.isArray(bucket)) {
|
||||
bucket.push({ dispose: remove });
|
||||
bucket.push({ dispose: () => this.remove(callback, context) });
|
||||
}
|
||||
}
|
||||
|
||||
public remove(callback: Function, context: any = null): void {
|
||||
if (!this._callbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
let foundCallbackWithDifferentContext = false;
|
||||
for (let i = 0, len = this._callbacks.length; i < len; i++) {
|
||||
if (this._callbacks[i] === callback) {
|
||||
if (this._contexts[i] === context) {
|
||||
// callback & context match => remove it
|
||||
this._callbacks.splice(i, 1);
|
||||
this._contexts.splice(i, 1);
|
||||
return;
|
||||
} else {
|
||||
foundCallbackWithDifferentContext = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundCallbackWithDifferentContext) {
|
||||
throw new Error('When adding a listener with a context, you should remove it with the same context');
|
||||
}
|
||||
return remove;
|
||||
}
|
||||
|
||||
public invoke(...args: any[]): any[] {
|
||||
@@ -28,12 +54,13 @@ export default class CallbackList {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const ret: any[] = [];
|
||||
const elements = this._callbacks.toArray();
|
||||
const ret: any[] = [],
|
||||
callbacks = this._callbacks.slice(0),
|
||||
contexts = this._contexts.slice(0);
|
||||
|
||||
for (const [callback, context] of elements) {
|
||||
for (let i = 0, len = callbacks.length; i < len; i++) {
|
||||
try {
|
||||
ret.push(callback.apply(context, args));
|
||||
ret.push(callbacks[i].apply(contexts[i], args));
|
||||
} catch (e) {
|
||||
onUnexpectedError(e);
|
||||
}
|
||||
@@ -41,20 +68,19 @@ export default class CallbackList {
|
||||
return ret;
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return !this._callbacks || this._callbacks.length === 0;
|
||||
}
|
||||
|
||||
public entries(): [Function, any][] {
|
||||
if (!this._callbacks) {
|
||||
return [];
|
||||
}
|
||||
return this._callbacks
|
||||
? this._callbacks.toArray()
|
||||
: [];
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return !this._callbacks || this._callbacks.isEmpty();
|
||||
return this._callbacks.map((fn, index) => <[Function, any]>[fn, this._contexts[index]]);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this._callbacks = undefined;
|
||||
this._contexts = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@ export class Emitter<T> {
|
||||
this._options.onFirstListenerAdd(this);
|
||||
}
|
||||
|
||||
const remove = this._callbacks.add(listener, thisArgs);
|
||||
this._callbacks.add(listener, thisArgs);
|
||||
|
||||
if (firstListener && this._options && this._options.onFirstListenerDidAdd) {
|
||||
this._options.onFirstListenerDidAdd(this);
|
||||
@@ -97,7 +97,7 @@ export class Emitter<T> {
|
||||
dispose: () => {
|
||||
result.dispose = Emitter._noop;
|
||||
if (!this._disposed) {
|
||||
remove();
|
||||
this._callbacks.remove(listener, thisArgs);
|
||||
if (this._options && this._options.onLastListenerRemove && this._callbacks.isEmpty()) {
|
||||
this._options.onLastListenerRemove(this);
|
||||
}
|
||||
@@ -545,4 +545,4 @@ export class Relay<T> implements IDisposable {
|
||||
this.disposable.dispose();
|
||||
this.emitter.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
class Node<E> {
|
||||
element: E;
|
||||
next: Node<E>;
|
||||
prev: Node<E>;
|
||||
|
||||
constructor(element: E) {
|
||||
this.element = element;
|
||||
}
|
||||
}
|
||||
|
||||
export class LinkedList<E> {
|
||||
|
||||
private _first: Node<E>;
|
||||
private _last: Node<E>;
|
||||
|
||||
isEmpty(): boolean {
|
||||
return !this._first;
|
||||
}
|
||||
|
||||
insert(element: E) {
|
||||
const newNode = new Node(element);
|
||||
if (!this._first) {
|
||||
this._first = newNode;
|
||||
this._last = newNode;
|
||||
} else {
|
||||
const oldLast = this._last;
|
||||
this._last = newNode;
|
||||
newNode.prev = oldLast;
|
||||
oldLast.next = newNode;
|
||||
}
|
||||
|
||||
return () => {
|
||||
|
||||
for (let candidate = this._first; candidate instanceof Node; candidate = candidate.next) {
|
||||
if (candidate !== newNode) {
|
||||
continue;
|
||||
}
|
||||
if (candidate.prev && candidate.next) {
|
||||
// middle
|
||||
let anchor = candidate.prev;
|
||||
anchor.next = candidate.next;
|
||||
candidate.next.prev = anchor;
|
||||
|
||||
} else if (!candidate.prev && !candidate.next) {
|
||||
// only node
|
||||
this._first = undefined;
|
||||
this._last = undefined;
|
||||
|
||||
} else if (!candidate.next) {
|
||||
// last
|
||||
this._last = this._last.prev;
|
||||
this._last.next = undefined;
|
||||
|
||||
} else if (!candidate.prev) {
|
||||
// first
|
||||
this._first = this._first.next;
|
||||
this._first.prev = undefined;
|
||||
}
|
||||
|
||||
// done
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
iterator() {
|
||||
let _done: boolean;
|
||||
let _value: E;
|
||||
let element = {
|
||||
get done() { return _done; },
|
||||
get value() { return _value; }
|
||||
};
|
||||
let node = this._first;
|
||||
return {
|
||||
next(): { done: boolean; value: E } {
|
||||
if (!node) {
|
||||
_done = true;
|
||||
_value = undefined;
|
||||
} else {
|
||||
_done = false;
|
||||
_value = node.element;
|
||||
node = node.next;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
toArray(): E[] {
|
||||
let result: E[] = [];
|
||||
for (let node = this._first; node instanceof Node; node = node.next) {
|
||||
result.push(node.element);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -179,29 +179,6 @@ suite('Event', function () {
|
||||
}
|
||||
});
|
||||
|
||||
test('reusing event function and context', function () {
|
||||
let counter = 0;
|
||||
function listener() {
|
||||
counter += 1;
|
||||
}
|
||||
const context = {};
|
||||
|
||||
let emitter = new Emitter();
|
||||
let reg1 = emitter.event(listener, context);
|
||||
let reg2 = emitter.event(listener, context);
|
||||
|
||||
emitter.fire();
|
||||
assert.equal(counter, 2);
|
||||
|
||||
reg1.dispose();
|
||||
emitter.fire();
|
||||
assert.equal(counter, 3);
|
||||
|
||||
reg2.dispose();
|
||||
emitter.fire();
|
||||
assert.equal(counter, 3);
|
||||
});
|
||||
|
||||
test('Debounce Event', function (done: () => void) {
|
||||
let doc = new Samples.Document3();
|
||||
|
||||
@@ -683,4 +660,4 @@ suite('Event utils', () => {
|
||||
assert.deepEqual(result, [1, 2, 3, 4, 5]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,72 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { LinkedList } from 'vs/base/common/linkedList';
|
||||
|
||||
suite('LinkedList', function () {
|
||||
|
||||
function assertElements<E>(list: LinkedList<E>, ...elements: E[]) {
|
||||
// first: assert toArray
|
||||
assert.deepEqual(list.toArray(), elements);
|
||||
|
||||
// second: assert iterator
|
||||
for (let iter = list.iterator(), element = iter.next(); !element.done; element = iter.next()) {
|
||||
assert.equal(elements.shift(), element.value);
|
||||
}
|
||||
assert.equal(elements.length, 0);
|
||||
}
|
||||
|
||||
test('Insert/Iter', function () {
|
||||
const list = new LinkedList<number>();
|
||||
list.insert(0);
|
||||
list.insert(1);
|
||||
list.insert(2);
|
||||
assertElements(list, 0, 1, 2);
|
||||
});
|
||||
|
||||
test('Insert/Remove', function () {
|
||||
let list = new LinkedList<number>();
|
||||
let disp = list.insert(0);
|
||||
list.insert(1);
|
||||
list.insert(2);
|
||||
disp();
|
||||
assertElements(list, 1, 2);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.insert(0);
|
||||
disp = list.insert(1);
|
||||
list.insert(2);
|
||||
disp();
|
||||
assertElements(list, 0, 2);
|
||||
|
||||
list = new LinkedList<number>();
|
||||
list.insert(0);
|
||||
list.insert(1);
|
||||
disp = list.insert(2);
|
||||
disp();
|
||||
assertElements(list, 0, 1);
|
||||
});
|
||||
|
||||
test('Insert/toArray', function () {
|
||||
let list = new LinkedList<string>();
|
||||
list.insert('foo');
|
||||
list.insert('bar');
|
||||
list.insert('far');
|
||||
list.insert('boo');
|
||||
|
||||
assert.deepEqual(
|
||||
list.toArray(),
|
||||
[
|
||||
'foo',
|
||||
'bar',
|
||||
'far',
|
||||
'boo',
|
||||
]
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user