Path: blob/main/src/vs/workbench/contrib/notebook/browser/notebookExtensionPoint.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { IJSONSchema } from '../../../../base/common/jsonSchema.js';6import * as nls from '../../../../nls.js';7import { ExtensionsRegistry } from '../../../services/extensions/common/extensionsRegistry.js';8import { NotebookEditorPriority, ContributedNotebookRendererEntrypoint, RendererMessagingSpec } from '../common/notebookCommon.js';9import { Disposable } from '../../../../base/common/lifecycle.js';10import { IExtensionManifest } from '../../../../platform/extensions/common/extensions.js';11import { SyncDescriptor } from '../../../../platform/instantiation/common/descriptors.js';12import { IExtensionFeatureTableRenderer, IRenderedData, ITableData, IRowData, IExtensionFeaturesRegistry, Extensions } from '../../../services/extensionManagement/common/extensionFeatures.js';13import { Registry } from '../../../../platform/registry/common/platform.js';1415const NotebookEditorContribution = Object.freeze({16type: 'type',17displayName: 'displayName',18selector: 'selector',19priority: 'priority',20});2122export interface INotebookEditorContribution {23readonly [NotebookEditorContribution.type]: string;24readonly [NotebookEditorContribution.displayName]: string;25readonly [NotebookEditorContribution.selector]?: readonly { filenamePattern?: string; excludeFileNamePattern?: string }[];26readonly [NotebookEditorContribution.priority]?: string;27}2829const NotebookRendererContribution = Object.freeze({30id: 'id',31displayName: 'displayName',32mimeTypes: 'mimeTypes',33entrypoint: 'entrypoint',34hardDependencies: 'dependencies',35optionalDependencies: 'optionalDependencies',36requiresMessaging: 'requiresMessaging',37});3839export interface INotebookRendererContribution {40readonly [NotebookRendererContribution.id]?: string;41readonly [NotebookRendererContribution.displayName]: string;42readonly [NotebookRendererContribution.mimeTypes]?: readonly string[];43readonly [NotebookRendererContribution.entrypoint]: ContributedNotebookRendererEntrypoint;44readonly [NotebookRendererContribution.hardDependencies]: readonly string[];45readonly [NotebookRendererContribution.optionalDependencies]: readonly string[];46readonly [NotebookRendererContribution.requiresMessaging]: RendererMessagingSpec;47}4849const NotebookPreloadContribution = Object.freeze({50type: 'type',51entrypoint: 'entrypoint',52localResourceRoots: 'localResourceRoots',53});5455interface INotebookPreloadContribution {56readonly [NotebookPreloadContribution.type]: string;57readonly [NotebookPreloadContribution.entrypoint]: string;58readonly [NotebookPreloadContribution.localResourceRoots]: readonly string[];59}6061const notebookProviderContribution: IJSONSchema = {62description: nls.localize('contributes.notebook.provider', 'Contributes notebook document provider.'),63type: 'array',64defaultSnippets: [{ body: [{ type: '', displayName: '', 'selector': [{ 'filenamePattern': '' }] }] }],65items: {66type: 'object',67required: [68NotebookEditorContribution.type,69NotebookEditorContribution.displayName,70NotebookEditorContribution.selector,71],72properties: {73[NotebookEditorContribution.type]: {74type: 'string',75description: nls.localize('contributes.notebook.provider.viewType', 'Type of the notebook.'),76},77[NotebookEditorContribution.displayName]: {78type: 'string',79description: nls.localize('contributes.notebook.provider.displayName', 'Human readable name of the notebook.'),80},81[NotebookEditorContribution.selector]: {82type: 'array',83description: nls.localize('contributes.notebook.provider.selector', 'Set of globs that the notebook is for.'),84items: {85type: 'object',86properties: {87filenamePattern: {88type: 'string',89description: nls.localize('contributes.notebook.provider.selector.filenamePattern', 'Glob that the notebook is enabled for.'),90},91excludeFileNamePattern: {92type: 'string',93description: nls.localize('contributes.notebook.selector.provider.excludeFileNamePattern', 'Glob that the notebook is disabled for.')94}95}96}97},98[NotebookEditorContribution.priority]: {99type: 'string',100markdownDeprecationMessage: 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.'),101enum: [102NotebookEditorPriority.default,103NotebookEditorPriority.option,104],105markdownEnumDescriptions: [106nls.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.'),107nls.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.'),108],109default: 'default'110}111}112}113};114115const defaultRendererSnippet = Object.freeze({ id: '', displayName: '', mimeTypes: [''], entrypoint: '' });116117const notebookRendererContribution: IJSONSchema = {118description: nls.localize('contributes.notebook.renderer', 'Contributes notebook output renderer provider.'),119type: 'array',120defaultSnippets: [{ body: [defaultRendererSnippet] }],121items: {122defaultSnippets: [{ body: defaultRendererSnippet }],123allOf: [124{125type: 'object',126required: [127NotebookRendererContribution.id,128NotebookRendererContribution.displayName,129],130properties: {131[NotebookRendererContribution.id]: {132type: 'string',133description: nls.localize('contributes.notebook.renderer.viewType', 'Unique identifier of the notebook output renderer.'),134},135[NotebookRendererContribution.displayName]: {136type: 'string',137description: nls.localize('contributes.notebook.renderer.displayName', 'Human readable name of the notebook output renderer.'),138},139[NotebookRendererContribution.hardDependencies]: {140type: 'array',141uniqueItems: true,142items: { type: 'string' },143markdownDescription: 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.'),144},145[NotebookRendererContribution.optionalDependencies]: {146type: 'array',147uniqueItems: true,148items: { type: 'string' },149markdownDescription: 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.'),150},151[NotebookRendererContribution.requiresMessaging]: {152default: 'never',153enum: [154'always',155'optional',156'never',157],158enumDescriptions: [159nls.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.'),160nls.localize('contributes.notebook.renderer.requiresMessaging.optional', 'The renderer is better with messaging available, but it\'s not requried.'),161nls.localize('contributes.notebook.renderer.requiresMessaging.never', 'The renderer does not require messaging.'),162],163description: 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.'),164},165}166},167{168oneOf: [169{170required: [171NotebookRendererContribution.entrypoint,172NotebookRendererContribution.mimeTypes,173],174properties: {175[NotebookRendererContribution.mimeTypes]: {176type: 'array',177description: nls.localize('contributes.notebook.selector', 'Set of globs that the notebook is for.'),178items: {179type: 'string'180}181},182[NotebookRendererContribution.entrypoint]: {183description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),184type: 'string',185},186}187},188{189required: [190NotebookRendererContribution.entrypoint,191],192properties: {193[NotebookRendererContribution.entrypoint]: {194description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),195type: 'object',196required: ['extends', 'path'],197properties: {198extends: {199type: 'string',200description: nls.localize('contributes.notebook.renderer.entrypoint.extends', 'Existing renderer that this one extends.'),201},202path: {203type: 'string',204description: nls.localize('contributes.notebook.renderer.entrypoint', 'File to load in the webview to render the extension.'),205},206}207},208}209}210]211}212]213}214};215216const notebookPreloadContribution: IJSONSchema = {217description: nls.localize('contributes.preload.provider', 'Contributes notebook preloads.'),218type: 'array',219defaultSnippets: [{ body: [{ type: '', entrypoint: '' }] }],220items: {221type: 'object',222required: [223NotebookPreloadContribution.type,224NotebookPreloadContribution.entrypoint225],226properties: {227[NotebookPreloadContribution.type]: {228type: 'string',229description: nls.localize('contributes.preload.provider.viewType', 'Type of the notebook.'),230},231[NotebookPreloadContribution.entrypoint]: {232type: 'string',233description: nls.localize('contributes.preload.entrypoint', 'Path to file loaded in the webview.'),234},235[NotebookPreloadContribution.localResourceRoots]: {236type: 'array',237items: { type: 'string' },238description: nls.localize('contributes.preload.localResourceRoots', 'Paths to additional resources that should be allowed in the webview.'),239},240}241}242};243244export const notebooksExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookEditorContribution[]>({245extensionPoint: 'notebooks',246jsonSchema: notebookProviderContribution,247activationEventsGenerator: (contribs: INotebookEditorContribution[], result: { push(item: string): void }) => {248for (const contrib of contribs) {249if (contrib.type) {250result.push(`onNotebookSerializer:${contrib.type}`);251}252}253}254});255256export const notebookRendererExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookRendererContribution[]>({257extensionPoint: 'notebookRenderer',258jsonSchema: notebookRendererContribution,259activationEventsGenerator: (contribs: INotebookRendererContribution[], result: { push(item: string): void }) => {260for (const contrib of contribs) {261if (contrib.id) {262result.push(`onRenderer:${contrib.id}`);263}264}265}266});267268export const notebookPreloadExtensionPoint = ExtensionsRegistry.registerExtensionPoint<INotebookPreloadContribution[]>({269extensionPoint: 'notebookPreload',270jsonSchema: notebookPreloadContribution,271});272273class NotebooksDataRenderer extends Disposable implements IExtensionFeatureTableRenderer {274275readonly type = 'table';276277shouldRender(manifest: IExtensionManifest): boolean {278return !!manifest.contributes?.notebooks;279}280281render(manifest: IExtensionManifest): IRenderedData<ITableData> {282const contrib = manifest.contributes?.notebooks || [];283if (!contrib.length) {284return { data: { headers: [], rows: [] }, dispose: () => { } };285}286287const headers = [288nls.localize('Notebook id', "ID"),289nls.localize('Notebook name', "Name"),290];291292const rows: IRowData[][] = contrib293.sort((a, b) => a.type.localeCompare(b.type))294.map(notebook => {295return [296notebook.type,297notebook.displayName298];299});300301return {302data: {303headers,304rows305},306dispose: () => { }307};308}309}310311class NotebookRenderersDataRenderer extends Disposable implements IExtensionFeatureTableRenderer {312313readonly type = 'table';314315shouldRender(manifest: IExtensionManifest): boolean {316return !!manifest.contributes?.notebookRenderer;317}318319render(manifest: IExtensionManifest): IRenderedData<ITableData> {320const contrib = manifest.contributes?.notebookRenderer || [];321if (!contrib.length) {322return { data: { headers: [], rows: [] }, dispose: () => { } };323}324325const headers = [326nls.localize('Notebook renderer name', "Name"),327nls.localize('Notebook mimetypes', "Mimetypes"),328];329330const rows: IRowData[][] = contrib331.sort((a, b) => a.displayName.localeCompare(b.displayName))332.map(notebookRenderer => {333return [334notebookRenderer.displayName,335notebookRenderer.mimeTypes.join(',')336];337});338339return {340data: {341headers,342rows343},344dispose: () => { }345};346}347}348349Registry.as<IExtensionFeaturesRegistry>(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({350id: 'notebooks',351label: nls.localize('notebooks', "Notebooks"),352access: {353canToggle: false354},355renderer: new SyncDescriptor(NotebooksDataRenderer),356});357358Registry.as<IExtensionFeaturesRegistry>(Extensions.ExtensionFeaturesRegistry).registerExtensionFeature({359id: 'notebookRenderer',360label: nls.localize('notebookRenderer', "Notebook Renderers"),361access: {362canToggle: false363},364renderer: new SyncDescriptor(NotebookRenderersDataRenderer),365});366367368