提交 40ebb1a8 编写于 作者: R rebornix

content provider registration without static contribution.

上级 3156f1fb
......@@ -1791,7 +1791,12 @@ declare module 'vscode' {
* Controls if a meetadata property change will trigger notebook document content change and if it will be used in the diff editor
* Default to false. If the content provider doesn't persisit a metadata property in the file document, it should be set to true.
*/
transientMetadata: { [K in keyof NotebookCellMetadata]?: boolean }
transientMetadata: { [K in keyof NotebookCellMetadata]?: boolean };
/**
* Not ready for production or development use yet.
*/
viewOptions?: { displayName: string; filenamePattern: GlobPattern | { include: GlobPattern; exclude: GlobPattern; }; exclusive?: boolean; };
}
): Disposable;
......
......@@ -6,6 +6,7 @@
import * as DOM from 'vs/base/browser/dom';
import { CancellationToken } from 'vs/base/common/cancellation';
import { Emitter } from 'vs/base/common/event';
import { IRelativePattern } from 'vs/base/common/glob';
import { combinedDisposable, Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { ResourceMap } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
......@@ -18,7 +19,7 @@ import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookB
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { INotebookCellStatusBarService } from 'vs/workbench/contrib/notebook/common/notebookCellStatusBarService';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { ACCESSIBLE_NOTEBOOK_DISPLAY_ORDER, CellEditType, DisplayOrderKey, ICellEditOperation, ICellRange, IEditor, IMainCellDto, INotebookDecorationRenderOptions, INotebookDocumentFilter, INotebookExclusiveDocumentFilter, NotebookCellOutputsSplice, NotebookCellsChangeType, NOTEBOOK_DISPLAY_ORDER, TransientMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IMainNotebookController, INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
......@@ -443,10 +444,15 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo
// }
}
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: { transientOutputs: boolean; transientMetadata: TransientMetadata }): Promise<void> {
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: {
transientOutputs: boolean;
transientMetadata: TransientMetadata;
viewOptions?: { displayName: string; filenamePattern: string | IRelativePattern | INotebookExclusiveDocumentFilter; exclusive: boolean; };
}): Promise<void> {
const controller: IMainNotebookController = {
supportBackup,
options,
viewOptions: options.viewOptions,
reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => {
const data = await this._proxy.$resolveNotebookData(viewType, mainthreadTextModel.uri);
mainthreadTextModel.updateLanguages(data.languages);
......
......@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
......@@ -735,7 +735,11 @@ export enum NotebookEditorRevealType {
export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarEntry>;
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: { transientOutputs: boolean; transientMetadata: TransientMetadata }): Promise<void>;
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: {
transientOutputs: boolean;
transientMetadata: TransientMetadata;
viewOptions?: { displayName: string; filenamePattern: string | IRelativePattern | INotebookExclusiveDocumentFilter; exclusive: boolean; };
}): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
......
......@@ -304,6 +304,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
options?: {
transientOutputs: boolean;
transientMetadata: { [K in keyof NotebookCellMetadata]?: boolean };
viewOptions?: { displayName: string; filenamePattern: vscode.GlobPattern | { include: vscode.GlobPattern; exclude: vscode.GlobPattern }; exclusive?: boolean; };
}
): vscode.Disposable {
......@@ -332,7 +333,14 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
const supportBackup = !!provider.backupNotebook;
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, { transientOutputs: options?.transientOutputs || false, transientMetadata: options?.transientMetadata || {} });
const viewOptionsFilenamePattern = typeConverters.NotebookExclusiveDocumentPattern.from(options?.viewOptions?.filenamePattern);
console.warn(`Notebook content provider view options file name pattern is valid ${options?.viewOptions?.filenamePattern}`);
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation, description: extension.description }, viewType, supportBackup, {
transientOutputs: options?.transientOutputs || false,
transientMetadata: options?.transientMetadata || {},
viewOptions: options?.viewOptions && viewOptionsFilenamePattern ? { displayName: options.viewOptions.displayName, filenamePattern: viewOptionsFilenamePattern, exclusive: options.viewOptions.exclusive || false } : undefined
});
return new extHostTypes.Disposable(() => {
listener.dispose();
......
......@@ -344,7 +344,7 @@ export class NotebookContribution extends Disposable implements IWorkbenchContri
}
const infos = this.notebookService.getContributedNotebookProviders(notebookUri);
let info = infos.find(info => !id || info.id === id);
let info = infos.find(info => (!id || info.id === id) && info.exclusive) || infos.find(info => !id || info.id === id);
if (!info && id !== undefined) {
info = this.notebookService.getContributedNotebookProvider(id);
......
......@@ -121,7 +121,9 @@ export class NotebookProviderInfoStore extends Disposable {
providerExtensionId: extension.description.identifier.value,
providerDescription: extension.description.description,
providerDisplayName: extension.description.isBuiltin ? nls.localize('builtinProviderDisplayName', "Built-in") : extension.description.displayName || extension.description.identifier.value,
providerExtensionLocation: extension.description.extensionLocation
providerExtensionLocation: extension.description.extensionLocation,
dynamicContribution: false,
exclusive: false
}));
}
}
......@@ -175,6 +177,10 @@ export class NotebookProviderInfoStore extends Disposable {
return;
}
this._contributedEditors.set(info.id, info);
const mementoObject = this._memento.getMemento(StorageScope.GLOBAL);
mementoObject[NotebookProviderInfoStore.CUSTOM_EDITORS_ENTRY_ID] = Array.from(this._contributedEditors.values());
this._memento.saveMemento();
}
getContributedNotebook(resource: URI): readonly NotebookProviderInfo[] {
......@@ -550,6 +556,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu
if (!this._notebookProviders.has(viewType)) {
await this._extensionService.whenInstalledExtensionsRegistered();
// notebook providers/kernels/renderers might use `*` as activation event.
// TODO, only activate by `*` if this._notebookProviders.get(viewType).dynamicContribution === true
await this._extensionService.activateByEvent(`*`);
// this awaits full activation of all matching extensions
await this._extensionService.activateByEvent(`onNotebook:${viewType}`);
......@@ -562,6 +569,23 @@ export class NotebookService extends Disposable implements INotebookService, ICu
registerNotebookController(viewType: string, extensionData: NotebookExtensionDescription, controller: IMainNotebookController): IDisposable {
this._notebookProviders.set(viewType, { extensionData, controller });
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({
displayName: controller.viewOptions.displayName,
id: viewType,
priority: NotebookEditorPriority.default,
selector: [{ filenamePattern: controller.viewOptions.filenamePattern }],
providerExtensionId: extensionData.id.value,
providerDescription: extensionData.description,
providerDisplayName: extensionData.id.value,
providerExtensionLocation: URI.revive(extensionData.location),
dynamicContribution: true,
exclusive: controller.viewOptions.exclusive
}));
}
this._onDidChangeViewTypes.fire();
return toDisposable(() => {
this._notebookProviders.delete(viewType);
......
......@@ -778,7 +778,7 @@ export interface INotebookDocumentFilter {
//TODO@rebornix test
function isDocumentExcludePattern(filenamePattern: string | glob.IRelativePattern | INotebookExclusiveDocumentFilter): filenamePattern is { include: string | glob.IRelativePattern; exclude: string | glob.IRelativePattern; } {
export function isDocumentExcludePattern(filenamePattern: string | glob.IRelativePattern | INotebookExclusiveDocumentFilter): filenamePattern is { include: string | glob.IRelativePattern; exclude: string | glob.IRelativePattern; } {
const arg = filenamePattern as INotebookExclusiveDocumentFilter;
if ((typeof arg.include === 'string' || glob.isRelativePattern(arg.include))
......
......@@ -64,8 +64,15 @@ export class NotebookModelResolverService implements INotebookEditorModelResolve
const existingViewType = this._notebookService.getNotebookTextModel(resource)?.viewType;
if (!viewType) {
viewType = existingViewType ?? this._notebookService.getContributedNotebookProviders(resource)[0]?.id;
if (existingViewType) {
viewType = existingViewType;
} else {
const providers = this._notebookService.getContributedNotebookProviders(resource);
const exclusiveProvider = providers.find(provider => provider.exclusive);
viewType = exclusiveProvider?.id || providers[0]?.id;
}
}
if (!viewType) {
throw new Error(`Missing viewType for '${resource}'`);
}
......
......@@ -6,10 +6,10 @@
import * as glob from 'vs/base/common/glob';
import { URI } from 'vs/base/common/uri';
import { basename } from 'vs/base/common/path';
import { NotebookEditorPriority } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookExclusiveDocumentFilter, isDocumentExcludePattern, NotebookEditorPriority } from 'vs/workbench/contrib/notebook/common/notebookCommon';
export interface NotebookSelector {
readonly filenamePattern?: string;
readonly filenamePattern?: string | glob.IRelativePattern | INotebookExclusiveDocumentFilter;
readonly excludeFileNamePattern?: string;
}
......@@ -22,6 +22,8 @@ export interface NotebookEditorDescriptor {
readonly providerDescription?: string;
readonly providerDisplayName: string;
readonly providerExtensionLocation: URI;
readonly dynamicContribution: boolean;
readonly exclusive: boolean;
}
export class NotebookProviderInfo implements NotebookEditorDescriptor {
......@@ -35,6 +37,8 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor {
readonly providerDescription?: string;
readonly providerDisplayName: string;
readonly providerExtensionLocation: URI;
readonly dynamicContribution: boolean;
readonly exclusive: boolean;
constructor(descriptor: NotebookEditorDescriptor) {
this.id = descriptor.id;
......@@ -45,6 +49,8 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor {
this.providerDescription = descriptor.providerDescription;
this.providerDisplayName = descriptor.providerDisplayName;
this.providerExtensionLocation = descriptor.providerExtensionLocation;
this.dynamicContribution = descriptor.dynamicContribution;
this.exclusive = descriptor.exclusive;
}
matches(resource: URI): boolean {
......@@ -52,7 +58,11 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor {
}
static selectorMatches(selector: NotebookSelector, resource: URI): boolean {
if (selector.filenamePattern) {
if (!selector.filenamePattern) {
return false;
}
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())) {
......@@ -64,6 +74,19 @@ export class NotebookProviderInfo implements NotebookEditorDescriptor {
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 (glob.match(filenamePattern, basename(resource.fsPath).toLowerCase())) {
if (excludeFilenamePattern) {
if (glob.match(excludeFilenamePattern, basename(resource.fsPath).toLowerCase())) {
return false;
}
}
return true;
}
return false;
}
}
......@@ -10,19 +10,21 @@ import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.pr
import { Event } from 'vs/base/common/event';
import {
INotebookTextModel, INotebookRendererInfo,
IEditor, ICellEditOperation, NotebookCellOutputsSplice, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions
IEditor, ICellEditOperation, NotebookCellOutputsSplice, INotebookKernelProvider, INotebookKernelInfo2, TransientMetadata, NotebookDataDto, TransientOptions, INotebookDecorationRenderOptions, INotebookExclusiveDocumentFilter
} from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
import { CancellationToken } from 'vs/base/common/cancellation';
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
import { IDisposable } from 'vs/base/common/lifecycle';
import { NotebookOutputRendererInfo } from 'vs/workbench/contrib/notebook/common/notebookOutputRenderer';
import { IRelativePattern } from 'vs/base/common/glob';
export const INotebookService = createDecorator<INotebookService>('notebookService');
export interface IMainNotebookController {
supportBackup: boolean;
viewOptions?: { displayName: string; filenamePattern: string | IRelativePattern | INotebookExclusiveDocumentFilter; exclusive: boolean; };
options: { transientOutputs: boolean; transientMetadata: TransientMetadata; };
resolveNotebookDocument(viewType: string, uri: URI, backupId?: string): Promise<{ data: NotebookDataDto, transientOptions: TransientOptions }>;
reloadNotebook(mainthreadTextModel: NotebookTextModel): Promise<void>;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册