Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/services/notebookRendererMessagingServiceImpl.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Emitter } from '../../../../../base/common/event.js';
7
import { Disposable } from '../../../../../base/common/lifecycle.js';
8
import { INotebookRendererMessagingService, IScopedRendererMessaging } from '../../common/notebookRendererMessagingService.js';
9
import { IExtensionService } from '../../../../services/extensions/common/extensions.js';
10
11
type MessageToSend = { editorId: string; rendererId: string; message: unknown };
12
13
export class NotebookRendererMessagingService extends Disposable implements INotebookRendererMessagingService {
14
declare _serviceBrand: undefined;
15
/**
16
* Activation promises. Maps renderer IDs to a queue of messages that should
17
* be sent once activation finishes, or undefined if activation is complete.
18
*/
19
private readonly activations = new Map<string /* rendererId */, undefined | MessageToSend[]>();
20
private readonly scopedMessaging = new Map</* editorId */ string, IScopedRendererMessaging>();
21
private readonly postMessageEmitter = this._register(new Emitter<MessageToSend>());
22
public readonly onShouldPostMessage = this.postMessageEmitter.event;
23
24
constructor(
25
@IExtensionService private readonly extensionService: IExtensionService
26
) {
27
super();
28
}
29
30
/** @inheritdoc */
31
public receiveMessage(editorId: string | undefined, rendererId: string, message: unknown): Promise<boolean> {
32
if (editorId === undefined) {
33
const sends = [...this.scopedMessaging.values()].map(e => e.receiveMessageHandler?.(rendererId, message));
34
return Promise.all(sends).then(s => s.some(s => !!s));
35
}
36
37
return this.scopedMessaging.get(editorId)?.receiveMessageHandler?.(rendererId, message) ?? Promise.resolve(false);
38
}
39
40
/** @inheritdoc */
41
public prepare(rendererId: string) {
42
if (this.activations.has(rendererId)) {
43
return;
44
}
45
46
const queue: MessageToSend[] = [];
47
this.activations.set(rendererId, queue);
48
49
this.extensionService.activateByEvent(`onRenderer:${rendererId}`).then(() => {
50
for (const message of queue) {
51
this.postMessageEmitter.fire(message);
52
}
53
54
this.activations.set(rendererId, undefined);
55
});
56
}
57
58
/** @inheritdoc */
59
public getScoped(editorId: string): IScopedRendererMessaging {
60
const existing = this.scopedMessaging.get(editorId);
61
if (existing) {
62
return existing;
63
}
64
65
const messaging: IScopedRendererMessaging = {
66
postMessage: (rendererId, message) => this.postMessage(editorId, rendererId, message),
67
dispose: () => this.scopedMessaging.delete(editorId),
68
};
69
70
this.scopedMessaging.set(editorId, messaging);
71
return messaging;
72
}
73
74
private postMessage(editorId: string, rendererId: string, message: unknown): void {
75
if (!this.activations.has(rendererId)) {
76
this.prepare(rendererId);
77
}
78
79
const activation = this.activations.get(rendererId);
80
const toSend = { rendererId, editorId, message };
81
if (activation === undefined) {
82
this.postMessageEmitter.fire(toSend);
83
} else {
84
activation.push(toSend);
85
}
86
}
87
}
88
89