Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow to define error handler for misbehaving listener, adopt emitter#errorHandler for editor and notebook events #175881

Merged
merged 1 commit into from Mar 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/vs/base/common/event.ts
Expand Up @@ -573,6 +573,11 @@ export interface EmitterOptions {
* Optional function that's called *before* a listener is removed
*/
onWillRemoveListener?: Function;
/**
* Optional function that's called when a listener throws an error. Defaults to
* {@link onUnexpectedError}
*/
onListenerError?: (e: any) => void;
/**
* Number of listeners that are allowed before assuming a leak. Default to
* a globally configured value
Expand Down Expand Up @@ -874,7 +879,7 @@ export class Emitter<T> {
// the driver of this

if (!this._deliveryQueue) {
this._deliveryQueue = new PrivateEventDeliveryQueue();
this._deliveryQueue = new PrivateEventDeliveryQueue(this._options?.onListenerError);
}

for (const listener of this._listeners) {
Expand All @@ -899,8 +904,13 @@ export class Emitter<T> {
}

export class EventDeliveryQueue {

protected _queue = new LinkedList<EventDeliveryQueueElement>();

constructor(
private readonly _onListenerError: (e: any) => void = onUnexpectedError
) { }

get size(): number {
return this._queue.size;
}
Expand All @@ -925,7 +935,7 @@ export class EventDeliveryQueue {
try {
element.listener.invoke(element.event);
} catch (e) {
onUnexpectedError(e);
this._onListenerError(e);
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/vs/base/test/common/event.test.ts
Expand Up @@ -235,6 +235,27 @@ suite('Event', function () {
}
});

test('throwingListener (custom handler)', () => {

const allError: any[] = [];

const a = new Emitter<undefined>({
onListenerError(e) { allError.push(e); }
});
let hit = false;
a.event(function () {
// eslint-disable-next-line no-throw-literal
throw 9;
});
a.event(function () {
hit = true;
});
a.fire(undefined);
assert.strictEqual(hit, true);
assert.deepStrictEqual(allError, [9]);

});

test('reusing event function and context', function () {
let counter = 0;
function listener() {
Expand Down
9 changes: 5 additions & 4 deletions src/vs/workbench/api/common/extHostNotebook.ts
Expand Up @@ -26,6 +26,7 @@ import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/
import type * as vscode from 'vscode';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
import { ExtHostNotebookEditor } from './extHostNotebookEditor';
import { onUnexpectedExternalError } from 'vs/base/common/errors';



Expand All @@ -41,7 +42,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
private readonly _commandsConverter: CommandsConverter;

private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>();
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>({ onListenerError: onUnexpectedExternalError });
readonly onDidChangeActiveNotebookEditor = this._onDidChangeActiveNotebookEditor.event;

private _activeNotebookEditor: ExtHostNotebookEditor | undefined;
Expand All @@ -53,12 +54,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
return this._visibleNotebookEditors.map(editor => editor.apiEditor);
}

private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>();
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>({ onListenerError: onUnexpectedExternalError });
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>({ onListenerError: onUnexpectedExternalError });
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;

private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>({ onListenerError: onUnexpectedExternalError });
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;

private _statusBarCache = new Cache<IDisposable>('NotebookCellStatusBarCache');
Expand Down
5 changes: 3 additions & 2 deletions src/vs/workbench/api/common/extHostNotebookEditors.ts
Expand Up @@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookEditorsShape, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo } from 'vs/workbench/api/common/extHost.protocol';
Expand All @@ -13,8 +14,8 @@ import type * as vscode from 'vscode';

export class ExtHostNotebookEditors implements ExtHostNotebookEditorsShape {

private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>();
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>({ onListenerError: onUnexpectedExternalError });

readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
readonly onDidChangeNotebookEditorVisibleRanges = this._onDidChangeNotebookEditorVisibleRanges.event;
Expand Down
13 changes: 7 additions & 6 deletions src/vs/workbench/api/common/extHostTextEditors.ts
Expand Up @@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/

import * as arrays from 'vs/base/common/arrays';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
Expand All @@ -15,12 +16,12 @@ import * as vscode from 'vscode';

export class ExtHostEditors implements ExtHostEditorsShape {

private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>();
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>();
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>();
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>();
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>();
private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>({ onListenerError: onUnexpectedExternalError });

readonly onDidChangeTextEditorSelection: Event<vscode.TextEditorSelectionChangeEvent> = this._onDidChangeTextEditorSelection.event;
readonly onDidChangeTextEditorOptions: Event<vscode.TextEditorOptionsChangeEvent> = this._onDidChangeTextEditorOptions.event;
Expand Down