From c185f7ab939ca3007c62039dd70ec01862286b93 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 21 Sep 2020 11:58:46 -0700 Subject: [PATCH] command for fetching all notebook content providers. --- .../api/common/extHostApiCommands.ts | 29 ++++++++ .../api/common/extHostTypeConverters.ts | 18 +++++ .../notebook/browser/contrib/coreActions.ts | 42 +++++++++++- .../notebook/browser/extensionPoint.ts | 3 +- .../notebook/browser/notebookServiceImpl.ts | 20 ++++-- .../notebook/common/notebookProvider.ts | 66 ++++++++++++------- .../notebook/common/notebookService.ts | 2 +- 7 files changed, 148 insertions(+), 32 deletions(-) diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 956f358bcd5..26300e195f5 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -19,6 +19,7 @@ import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGro import { isFalsyOrEmpty } from 'vs/base/common/arrays'; import { IRange } from 'vs/editor/common/core/range'; import { IPosition } from 'vs/editor/common/core/position'; +import { TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; //#region --- NEW world @@ -312,6 +313,12 @@ export class ExtHostApiCommands { returns: 'A promise that resolves to an array of ColorPresentation objects.' }); + this._register('vscode.resolveNotebookContentProviders', this._resolveNotebookContentProviders, { + description: 'Resolve Notebook Content Providers', + args: [], + returns: 'A promise that resolves to an array of NotebookContentProvider static info objects.' + }); + // ----------------------------------------------------------------- // The following commands are registered on both sides separately. // @@ -480,6 +487,28 @@ export class ExtHostApiCommands { item.command ? this._commands.converter.fromInternal(item.command) : undefined); })); } + + private _resolveNotebookContentProviders(): Promise<{ + viewType: string; + displayName: string; + filenamePattern: vscode.NotebookFilenamePattern[]; + options: vscode.NotebookDocumentContentOptions; + }[] | undefined> { + return this._commands.executeCommand<{ + viewType: string; + displayName: string; + options: { transientOutputs: boolean; transientMetadata: TransientMetadata }; + filenamePattern: (string | types.RelativePattern | { include: string | types.RelativePattern, exclude: string | types.RelativePattern })[] + }[]>('_resolveNotebookContentProvider') + .then(tryMapWith(item => { + return { + viewType: item.viewType, + displayName: item.displayName, + options: { transientOutputs: item.options.transientOutputs, transientMetadata: item.options.transientMetadata }, + filenamePattern: item.filenamePattern.map(pattern => typeConverters.NotebookExclusiveDocumentPattern.to(pattern)) + }; + })); + } } function tryMapWith(f: (x: T) => R) { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 484bc6dd58b..f10f2fa7b89 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -1329,6 +1329,24 @@ export namespace NotebookExclusiveDocumentPattern { } + export function to(pattern: string | types.RelativePattern | { include: string | types.RelativePattern, exclude: string | types.RelativePattern }): { include: vscode.GlobPattern, exclude: vscode.GlobPattern } | vscode.GlobPattern { + if (typeof pattern === 'string') { + return pattern; + } + + if (isRelativePattern(pattern)) { + return { + base: pattern.base, + pattern: pattern.pattern + }; + } + + return { + include: pattern.include, + exclude: pattern.exclude + }; + } + function isExclusivePattern(obj: any): obj is { include: types.RelativePattern | undefined | null, exclude: types.RelativePattern | undefined | null } { const ep = obj as { include: vscode.GlobPattern, exclude: vscode.GlobPattern }; const include = GlobPattern.from(ep.include); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 455575b41af..6663e055304 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import * as glob from 'vs/base/common/glob'; import { URI } from 'vs/base/common/uri'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; @@ -12,7 +13,7 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { localize } from 'vs/nls'; import { Action2, IAction2Options, MenuId, MenuItemAction, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; -import { ICommandService } from 'vs/platform/commands/common/commands'; +import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { InputFocusedContext, InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -20,7 +21,7 @@ import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegis import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; import { BaseCellRenderTemplate, CellEditState, CellFocusMode, ICellViewModel, INotebookEditor, NOTEBOOK_CELL_INPUT_COLLAPSED, NOTEBOOK_CELL_EDITABLE, NOTEBOOK_CELL_HAS_OUTPUTS, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_MARKDOWN_EDIT_MODE, NOTEBOOK_CELL_OUTPUT_COLLAPSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_EDITABLE, NOTEBOOK_EDITOR_EXECUTING_NOTEBOOK, NOTEBOOK_EDITOR_FOCUSED, NOTEBOOK_EDITOR_RUNNABLE, NOTEBOOK_IS_ACTIVE_EDITOR, NOTEBOOK_OUTPUT_FOCUSED, EXPAND_CELL_CONTENT_COMMAND_ID, NOTEBOOK_CELL_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel'; -import { CellEditType, CellKind, ICellRange, NotebookCellMetadata, NotebookCellRunState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellEditType, CellKind, ICellRange, isDocumentExcludePattern, NotebookCellMetadata, NotebookCellRunState, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -1816,3 +1817,40 @@ registerAction2(class extends Action2 { } } }); + +CommandsRegistry.registerCommand('_resolveNotebookContentProvider', (accessor, args): { + viewType: string; + displayName: string; + options: { transientOutputs: boolean; transientMetadata: TransientMetadata }; + filenamePattern: (string | glob.IRelativePattern | { include: string | glob.IRelativePattern, exclude: string | glob.IRelativePattern })[] +}[] => { + const notebookService = accessor.get(INotebookService); + const contentProviders = notebookService.getContributedNotebookProviders(); + return contentProviders.map(provider => { + const filenamePatterns = provider.selectors.map(selector => { + if (typeof selector === 'string') { + return selector; + } + + if (glob.isRelativePattern(selector)) { + return selector; + } + + if (isDocumentExcludePattern(selector)) { + return { + include: selector.include, + exclude: selector.exclude + }; + } + + return null; + }).filter(pattern => pattern !== null) as (string | glob.IRelativePattern | { include: string | glob.IRelativePattern, exclude: string | glob.IRelativePattern })[]; + + return { + viewType: provider.id, + displayName: provider.displayName, + filenamePattern: filenamePatterns, + options: { transientMetadata: provider.options.transientMetadata, transientOutputs: provider.options.transientOutputs } + }; + }); +}); diff --git a/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts b/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts index 0cd2fc12149..97e3967422e 100644 --- a/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts +++ b/src/vs/workbench/contrib/notebook/browser/extensionPoint.ts @@ -6,7 +6,6 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import * as nls from 'vs/nls'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { NotebookSelector } from 'vs/workbench/contrib/notebook/common/notebookProvider'; import { NotebookEditorPriority } from 'vs/workbench/contrib/notebook/common/notebookCommon'; namespace NotebookEditorContribution { @@ -19,7 +18,7 @@ namespace NotebookEditorContribution { export interface INotebookEditorContribution { readonly [NotebookEditorContribution.viewType]: string; readonly [NotebookEditorContribution.displayName]: string; - readonly [NotebookEditorContribution.selector]?: readonly NotebookSelector[]; + readonly [NotebookEditorContribution.selector]?: readonly { filenamePattern?: string; excludeFileNamePattern?: string; }[]; readonly [NotebookEditorContribution.priority]?: string; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 7c0ff6d588b..9c42f974c8b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -569,20 +569,26 @@ export class NotebookService extends Disposable implements INotebookService, ICu if (controller.viewOptions && !this.notebookProviderInfoStore.get(viewType)) { // register this content provider to the static contribution, if it does not exist - this.notebookProviderInfoStore.add(new NotebookProviderInfo({ + const info = new NotebookProviderInfo({ displayName: controller.viewOptions.displayName, id: viewType, priority: NotebookEditorPriority.default, - selectors: controller.viewOptions.filenamePattern.map(pattern => ({ filenamePattern: pattern })), + selectors: [], providerExtensionId: extensionData.id.value, providerDescription: extensionData.description, providerDisplayName: extensionData.id.value, providerExtensionLocation: URI.revive(extensionData.location), dynamicContribution: true, exclusive: controller.viewOptions.exclusive - })); + }); + + info.update({ selectors: controller.viewOptions.filenamePattern }); + info.update({ options: controller.options }); + this.notebookProviderInfoStore.add(info); } + this.notebookProviderInfoStore.get(viewType)?.update({ options: controller.options }); + this._onDidChangeViewTypes.fire(); return toDisposable(() => { this._notebookProviders.delete(viewType); @@ -806,8 +812,12 @@ export class NotebookService extends Disposable implements INotebookService, ICu return this.notebookRenderersInfoStore.getContributedRenderer(mimeType); } - getContributedNotebookProviders(resource: URI): readonly NotebookProviderInfo[] { - return this.notebookProviderInfoStore.getContributedNotebook(resource); + getContributedNotebookProviders(resource?: URI): readonly NotebookProviderInfo[] { + if (resource) { + return this.notebookProviderInfoStore.getContributedNotebook(resource); + } + + return [...this.notebookProviderInfoStore]; } getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined { diff --git a/src/vs/workbench/contrib/notebook/common/notebookProvider.ts b/src/vs/workbench/contrib/notebook/common/notebookProvider.ts index 2a6a2beb211..d4cc1854475 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookProvider.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookProvider.ts @@ -6,17 +6,14 @@ import * as glob from 'vs/base/common/glob'; import { URI } from 'vs/base/common/uri'; import { basename } from 'vs/base/common/path'; -import { INotebookExclusiveDocumentFilter, isDocumentExcludePattern, NotebookEditorPriority } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookExclusiveDocumentFilter, isDocumentExcludePattern, NotebookEditorPriority, TransientOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon'; -export interface NotebookSelector { - readonly filenamePattern?: string | glob.IRelativePattern | INotebookExclusiveDocumentFilter; - readonly excludeFileNamePattern?: string; -} +export type NotebookSelector = string | glob.IRelativePattern | INotebookExclusiveDocumentFilter; export interface NotebookEditorDescriptor { readonly id: string; readonly displayName: string; - readonly selectors: readonly NotebookSelector[]; + readonly selectors: readonly { filenamePattern?: string; excludeFileNamePattern?: string; }[]; readonly priority: NotebookEditorPriority; readonly providerExtensionId?: string; readonly providerDescription?: string; @@ -26,11 +23,11 @@ export interface NotebookEditorDescriptor { readonly exclusive: boolean; } -export class NotebookProviderInfo implements NotebookEditorDescriptor { +export class NotebookProviderInfo { readonly id: string; readonly displayName: string; - readonly selectors: readonly NotebookSelector[]; + readonly priority: NotebookEditorPriority; // it's optional as the memento might not have it readonly providerExtensionId?: string; @@ -39,11 +36,22 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor { readonly providerExtensionLocation: URI; readonly dynamicContribution: boolean; readonly exclusive: boolean; + private _selectors: NotebookSelector[]; + get selectors() { + return this._selectors; + } + private _options: TransientOptions; + get options() { + return this._options; + } constructor(descriptor: NotebookEditorDescriptor) { this.id = descriptor.id; this.displayName = descriptor.displayName; - this.selectors = descriptor.selectors; + this._selectors = descriptor.selectors?.map(selector => ({ + include: selector.filenamePattern, + exclude: selector.excludeFileNamePattern || '' + })) || []; this.priority = descriptor.priority; this.providerExtensionId = descriptor.providerExtensionId; this.providerDescription = descriptor.providerDescription; @@ -51,6 +59,20 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor { this.providerExtensionLocation = descriptor.providerExtensionLocation; this.dynamicContribution = descriptor.dynamicContribution; this.exclusive = descriptor.exclusive; + this._options = { + transientMetadata: {}, + transientOutputs: false + }; + } + + update(args: { selectors?: NotebookSelector[]; options?: TransientOptions }) { + if (args.selectors) { + this._selectors = args.selectors; + } + + if (args.options) { + this._options = args.options; + } } matches(resource: URI): boolean { @@ -58,25 +80,25 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor { } static selectorMatches(selector: NotebookSelector, resource: URI): boolean { - if (!selector.filenamePattern) { - return false; + if (typeof selector === 'string') { + // filenamePattern + if (glob.match(selector.toLowerCase(), basename(resource.fsPath).toLowerCase())) { + return true; + } } - if (typeof selector.filenamePattern === 'string') { - if (glob.match(selector.filenamePattern.toLowerCase(), basename(resource.fsPath).toLowerCase())) { - if (selector.excludeFileNamePattern) { - if (glob.match(selector.excludeFileNamePattern.toLowerCase(), basename(resource.fsPath).toLowerCase())) { - // should exclude - - return false; - } - } + if (glob.isRelativePattern(selector)) { + if (glob.match(selector, basename(resource.fsPath).toLowerCase())) { return true; } } - let filenamePattern = isDocumentExcludePattern(selector.filenamePattern) ? selector.filenamePattern.include : (selector.filenamePattern as string | glob.IRelativePattern); - let excludeFilenamePattern = isDocumentExcludePattern(selector.filenamePattern) ? selector.filenamePattern.exclude : undefined; + if (!isDocumentExcludePattern(selector)) { + return false; + } + + let filenamePattern = selector.include; + let excludeFilenamePattern = selector.exclude; if (glob.match(filenamePattern, basename(resource.fsPath).toLowerCase())) { if (excludeFilenamePattern) { diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index 422fafd6c2e..51a80bc3ce4 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -59,7 +59,7 @@ export interface INotebookService { resolveNotebook(viewType: string, uri: URI, forceReload: boolean, backupId?: string): Promise; getNotebookTextModel(uri: URI): NotebookTextModel | undefined; getNotebookTextModels(): Iterable; - getContributedNotebookProviders(resource: URI): readonly NotebookProviderInfo[]; + getContributedNotebookProviders(resource?: URI): readonly NotebookProviderInfo[]; getContributedNotebookProvider(viewType: string): NotebookProviderInfo | undefined; getNotebookProviderResourceRoots(): URI[]; destoryNotebookDocument(viewType: string, notebook: INotebookTextModel): void; -- GitLab