Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.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 { IJSONSchema } from '../../../../base/common/jsonSchema.js';
7
import * as nls from '../../../../nls.js';
8
import { ExtensionsRegistry } from '../../../services/extensions/common/extensionsRegistry.js';
9
import { NotebookEditorPriority, ContributedNotebookRendererEntrypoint, RendererMessagingSpec } from '../common/notebookCommon.js';
10
import { Disposable } from '../../../../base/common/lifecycle.js';
11
import { IExtensionManifest } from '../../../../platform/extensions/common/extensions.js';
12
import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';
13
import { IExtensionFeatureTableRenderer, IRenderedData, ITableData, IRowData, IExtensionFeaturesRegistry, Extensions } from '../../../services/extensionManagement/common/extensionFeatures.js';
14
import { Registry } from '../../../../platform/registry/common/platform.js';
15
16
const NotebookEditorContribution = Object.freeze({
17
type: 'type',
18
displayName: 'displayName',
19
selector: 'selector',
20
priority: 'priority',
21
});
22
23
export interface INotebookEditorContribution {
24
readonly [NotebookEditorContribution.type]: string;
25
readonly [NotebookEditorContribution.displayName]: string;
26
readonly [NotebookEditorContribution.selector]?: readonly { filenamePattern?: string; excludeFileNamePattern?: string }[];
27
readonly [NotebookEditorContribution.priority]?: string;
28
}
29
30
const NotebookRendererContribution = Object.freeze({
31
id: 'id',
32
displayName: 'displayName',
33
mimeTypes: 'mimeTypes',
34
entrypoint: 'entrypoint',
35
hardDependencies: 'dependencies',
36
optionalDependencies: 'optionalDependencies',
37
requiresMessaging: 'requiresMessaging',
38
});
39
40
export interface INotebookRendererContribution {
41
readonly [NotebookRendererContribution.id]?: string;
42
readonly [NotebookRendererContribution.displayName]: string;
43
readonly [NotebookRendererContribution.mimeTypes]?: readonly string[];
44
readonly [NotebookRendererContribution.entrypoint]: ContributedNotebookRendererEntrypoint;
45
readonly [NotebookRendererContribution.hardDependencies]: readonly string[];
46
readonly [NotebookRendererContribution.optionalDependencies]: readonly string[];
47
readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec;
48
}
49
50
const NotebookPreloadContribution = Object.freeze({
51
type: 'type',
52
entrypoint: 'entrypoint',
53
localResourceRoots: 'localResourceRoots',
54
});
55
56
interface INotebookPreloadContribution {
57
readonly [NotebookPreloadContribution.type]: string;
58
readonly [NotebookPreloadContribution.entrypoint]: string;
59
readonly [NotebookPreloadContribution.localResourceRoots]: readonly string[];
60
}
61
62
const notebookProviderContribution: IJSONSchema = {
63
description: nls.localize('contributes.notebook.provider', 'Contributes notebook document provider.'),
64
type: 'array',
65
defaultSnippets: [{ body: [{ type: '', displayName: '', 'selector': [{ 'filenamePattern': '' }] }] }],
66
items: {
67
type: 'object',
68
required: [
69
NotebookEditorContribution.type,
70
NotebookEditorContribution.displayName,
71
NotebookEditorContribution.selector,
72
],
73
properties: {
74
[NotebookEditorContribution.type]: {
75
type: 'string',
76
description: nls.localize('contributes.notebook.provider.viewType', 'Type of the notebook.'),
77
},
78
[NotebookEditorContribution.displayName]: {
79
type: 'string',
80
description: nls.localize('contributes.notebook.provider.displayName', 'Human readable name of the notebook.'),
81
},
82
[NotebookEditorContribution.selector]: {
83
type: 'array',
84
description: nls.localize('contributes.notebook.provider.selector', 'Set of globs that the notebook is for.'),
85
items: {
86
type: 'object',
87
properties: {
88
filenamePattern: {
89
type: 'string',
90
description: nls.localize('contributes.notebook.provider.selector.filenamePattern', 'Glob that the notebook is enabled for.'),
91
},
92
excludeFileNamePattern: {
93
type: 'string',
94
description: nls.localize('contributes.notebook.selector.provider.excludeFileNamePattern', 'Glob that the notebook is disabled for.')
95
}
96
}
97
}
98
},
99
[NotebookEditorContribution.priority]: {
100
type: 'string',
101
markdownDeprecationMessage: nls.localize('contributes.priority', 'Controls if the custom editor is enabled automatically when the user opens a file. This may be overridden by users using the `workbench.editorAssociations` setting.'),
102
enum: [
103
NotebookEditorPriority.default,
104
NotebookEditorPriority.option,
105
],
106
markdownEnumDescriptions: [
107
nls.localize('contributes.priority.default', 'The editor is automatically used when the user opens a resource, provided that no other default custom editors are registered for that resource.'),
108
nls.localize('contributes.priority.option', 'The editor is not automatically used when the user opens a resource, but a user can switch to the editor using the `Reopen With` command.'),
109
],
110
default: 'default'
111
}
112
}
113
}
114
};
115
116
const defaultRendererSnippet = Object.freeze({ id: '', displayName: '', mimeTypes: [''], entrypoint: '' });
117
118
const notebookRendererContribution: IJSONSchema = {
119
description: nls.localize('contributes.notebook.renderer', 'Contributes notebook output renderer provider.'),
120
type: 'array',
121
defaultSnippets: [{ body: [defaultRendererSnippet] }],
122
items: {
123
defaultSnippets: [{ body: defaultRendererSnippet }],
124
allOf: [
125
{
126
type: 'object',
127
required: [
128
NotebookRendererContribution.id,
129
NotebookRendererContribution.displayName,
130
],
131
properties: {
132
[NotebookRendererContribution.id]: {
133
type: 'string',
134
description: nls.localize('contributes.notebook.renderer.viewType', 'Unique identifier of the notebook output renderer.'),
135
},
136
[NotebookRendererContribution.displayName]: {
137
type: 'string',
138
description: nls.localize('contributes.notebook.renderer.displayName', 'Human readable name of the notebook output renderer.'),
139
},
140
[NotebookRendererContribution.hardDependencies]: {
141
type: 'array',
142
uniqueItems: true,
143
items: { type: 'string' },
144
markdownDescription: nls.localize('contributes.notebook.renderer.hardDependencies', 'List of kernel dependencies the renderer requires. If any of the dependencies are present in the `NotebookKernel.preloads`, the renderer can be used.'),
145
},
146
[NotebookRendererContribution.optionalDependencies]: {
147
type: 'array',
148
uniqueItems: true,
149
items: { type: 'string' },
150
markdownDescription: nls.localize('contributes.notebook.renderer.optionalDependencies', 'List of soft kernel dependencies the renderer can make use of. If any of the dependencies are present in the `NotebookKernel.preloads`, the renderer will be preferred over renderers that don\'t interact with the kernel.'),
151
},
152
[NotebookRendererContribution.requiresMessaging]: {
153
default: 'never',
154
enum: [
155
'always',
156
'optional',
157
'never',
158
],
159
enumDescriptions: [
160
nls.localize('contributes.notebook.renderer.requiresMessaging.always', 'Messaging is required. The renderer will only be used when it\'s part of an extension that can be run in an extension host.'),
161
nls.localize('contributes.notebook.renderer.requiresMessaging.optional', 'The renderer is better with messaging available, but it\'s not requried.'),
162
nls.localize('contributes.notebook.renderer.requiresMessaging.never', 'The renderer does not require messaging.'),
163
],
164
description: nls.localize('contributes.notebook.renderer.requiresMessaging', 'Defines how and if the renderer needs to communicate with an extension host, via `createRendererMessaging`. Renderers with stronger messaging requirements may not work in all environments.'),
165
},
166
}
167
},
168
{
169
oneOf: [
170
{
171
required: [
172
NotebookRendererContribution.entrypoint,
173
NotebookRendererContribution.mimeTypes,
174
],
175
properties: {
176
[NotebookRendererContribution.mimeTypes]: {
177
type: 'array',
178
description: nls.localize('contributes.notebook.selector', 'Set of globs that the notebook is for.'),
179
items: {
180
type: 'string'
181
}
182
},
183
[NotebookRendererContribution.entrypoint]: {
184
description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
185
type: 'string',
186
},
187
}
188
},
189
{
190
required: [
191
NotebookRendererContribution.entrypoint,
192
],
193
properties: {
194
[NotebookRendererContribution.entrypoint]: {
195
description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
196
type: 'object',
197
required: ['extends', 'path'],
198
properties: {
199
extends: {
200
type: 'string',
201
description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'),
202
},
203
path: {
204
type: 'string',
205
description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),
206
},
207
}
208
},
209
}
210
}
211
]
212
}
213
]
214
}
215
};
216
217
const notebookPreloadContribution: IJSONSchema = {
218
description: nls.localize('contributes.preload.provider', 'Contributes notebook preloads.'),
219
type: 'array',
220
defaultSnippets: [{ body: [{ type: '', entrypoint: '' }] }],
221
items: {
222
type: 'object',
223
required: [
224
NotebookPreloadContribution.type,
225
NotebookPreloadContribution.entrypoint
226
],
227
properties: {
228
[NotebookPreloadContribution.type]: {
229
type: 'string',
230
description: nls.localize('contributes.preload.provider.viewType', 'Type of the notebook.'),
231
},
232
[NotebookPreloadContribution.entrypoint]: {
233
type: 'string',
234
description: nls.localize('contributes.preload.entrypoint', 'Path to file loaded in the webview.'),
235
},
236
[NotebookPreloadContribution.localResourceRoots]: {
237
type: 'array',
238
items: { type: 'string' },
239
description: nls.localize('contributes.preload.localResourceRoots', 'Paths to additional resources that should be allowed in the webview.'),
240
},
241
}
242
}
243
};
244
245
export const notebooksExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookEditorContribution[]>({
246
extensionPoint: 'notebooks',
247
jsonSchema: notebookProviderContribution,
248
activationEventsGenerator: (contribs: INotebookEditorContribution[], result: { push(item: string): void }) => {
249
for (const contrib of contribs) {
250
if (contrib.type) {
251
result.push(`onNotebookSerializer:${contrib.type}`);
252
}
253
}
254
}
255
});
256
257
export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookRendererContribution[]>({
258
extensionPoint: 'notebookRenderer',
259
jsonSchema: notebookRendererContribution,
260
activationEventsGenerator: (contribs: INotebookRendererContribution[], result: { push(item: string): void }) => {
261
for (const contrib of contribs) {
262
if (contrib.id) {
263
result.push(`onRenderer:${contrib.id}`);
264
}
265
}
266
}
267
});
268
269
export const notebookPreloadExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookPreloadContribution[]>({
270
extensionPoint: 'notebookPreload',
271
jsonSchema: notebookPreloadContribution,
272
});
273
274
class NotebooksDataRenderer extends Disposable implements IExtensionFeatureTableRenderer {
275
276
readonly type = 'table';
277
278
shouldRender(manifest: IExtensionManifest): boolean {
279
return !!manifest.contributes?.notebooks;
280
}
281
282
render(manifest: IExtensionManifest): IRenderedData<ITableData> {
283
const contrib = manifest.contributes?.notebooks || [];
284
if (!contrib.length) {
285
return { data: { headers: [], rows: [] }, dispose: () => { } };
286
}
287
288
const headers = [
289
nls.localize('Notebook id', "ID"),
290
nls.localize('Notebook name', "Name"),
291
];
292
293
const rows: IRowData[][] = contrib
294
.sort((a, b) => a.type.localeCompare(b.type))
295
.map(notebook => {
296
return [
297
notebook.type,
298
notebook.displayName
299
];
300
});
301
302
return {
303
data: {
304
headers,
305
rows
306
},
307
dispose: () => { }
308
};
309
}
310
}
311
312
class NotebookRenderersDataRenderer extends Disposable implements IExtensionFeatureTableRenderer {
313
314
readonly type = 'table';
315
316
shouldRender(manifest: IExtensionManifest): boolean {
317
return !!manifest.contributes?.notebookRenderer;
318
}
319
320
render(manifest: IExtensionManifest): IRenderedData<ITableData> {
321
const contrib = manifest.contributes?.notebookRenderer || [];
322
if (!contrib.length) {
323
return { data: { headers: [], rows: [] }, dispose: () => { } };
324
}
325
326
const headers = [
327
nls.localize('Notebook renderer name', "Name"),
328
nls.localize('Notebook mimetypes', "Mimetypes"),
329
];
330
331
const rows: IRowData[][] = contrib
332
.sort((a, b) => a.displayName.localeCompare(b.displayName))
333
.map(notebookRenderer => {
334
return [
335
notebookRenderer.displayName,
336
notebookRenderer.mimeTypes.join(',')
337
];
338
});
339
340
return {
341
data: {
342
headers,
343
rows
344
},
345
dispose: () => { }
346
};
347
}
348
}
349
350
Registry.as<IExtensionFeaturesRegistry>(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({
351
id: 'notebooks',
352
label: nls.localize('notebooks', "Notebooks"),
353
access: {
354
canToggle: false
355
},
356
renderer: new SyncDescriptor(NotebooksDataRenderer),
357
});
358
359
Registry.as<IExtensionFeaturesRegistry>(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({
360
id: 'notebookRenderer',
361
label: nls.localize('notebookRenderer', "Notebook Renderers"),
362
access: {
363
canToggle: false
364
},
365
renderer: new SyncDescriptor(NotebookRenderersDataRenderer),
366
});
367
368