mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-02 17:23:40 -05:00
Split up NotebookProvider into separate providers for handling file serialization and cell execution. (#17176)
This commit is contained in:
@@ -8,81 +8,45 @@
|
||||
import { nb } from 'azdata';
|
||||
|
||||
import * as json from 'vs/base/common/json';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
|
||||
import { JSONObject } from 'sql/workbench/services/notebook/common/jsonext';
|
||||
import { OutputTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { nbversion } from 'sql/workbench/services/notebook/common/notebookConstants';
|
||||
import { nbformat } from 'sql/workbench/services/notebook/common/nbformat';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
type MimeBundle = { [key: string]: string | string[] | undefined };
|
||||
|
||||
export class LocalContentManager implements nb.ContentManager {
|
||||
|
||||
constructor(@IFileService private readonly fileService: IFileService) { }
|
||||
constructor() { }
|
||||
|
||||
public async loadFromContentString(contentString: string): Promise<nb.INotebookContents> {
|
||||
let contents: JSONObject;
|
||||
if (contentString === '' || contentString === undefined) {
|
||||
public async deserializeNotebook(contents: string): Promise<nb.INotebookContents> {
|
||||
let jsonContents: JSONObject;
|
||||
if (contents === '' || contents === undefined) {
|
||||
return v4.createEmptyNotebook();
|
||||
} else {
|
||||
contents = this.parseFromJson(contentString);
|
||||
jsonContents = this.parseFromJson(contents);
|
||||
}
|
||||
if (contents) {
|
||||
if (contents.nbformat === 4) {
|
||||
return v4.readNotebook(<any>contents);
|
||||
} else if (contents.nbformat === 3) {
|
||||
return v3.readNotebook(<any>contents);
|
||||
if (jsonContents) {
|
||||
if (jsonContents.nbformat === 4) {
|
||||
return v4.readNotebook(<any>jsonContents);
|
||||
} else if (jsonContents.nbformat === 3) {
|
||||
return v3.readNotebook(<any>jsonContents);
|
||||
}
|
||||
if (contents.nbformat) {
|
||||
throw new TypeError(localize('nbformatNotRecognized', "nbformat v{0}.{1} not recognized", contents.nbformat as any, contents.nbformat_minor as any));
|
||||
if (jsonContents.nbformat) {
|
||||
throw new TypeError(localize('nbformatNotRecognized', "nbformat v{0}.{1} not recognized", jsonContents.nbformat as any, jsonContents.nbformat_minor as any));
|
||||
}
|
||||
}
|
||||
|
||||
// else, fallthrough condition
|
||||
throw new TypeError(localize('nbNotSupported', "This file does not have a valid notebook format"));
|
||||
|
||||
}
|
||||
|
||||
public async getNotebookContents(notebookUri: URI): Promise<nb.INotebookContents> {
|
||||
if (!notebookUri) {
|
||||
return undefined;
|
||||
}
|
||||
// Note: intentionally letting caller handle exceptions
|
||||
let notebookFileBuffer = await this.fileService.readFile(notebookUri);
|
||||
let stringContents = notebookFileBuffer.value.toString();
|
||||
let contents: JSONObject;
|
||||
if (stringContents === '' || stringContents === undefined) {
|
||||
// Empty?
|
||||
return v4.createEmptyNotebook();
|
||||
} else {
|
||||
contents = this.parseFromJson(stringContents);
|
||||
}
|
||||
|
||||
if (contents) {
|
||||
if (contents.nbformat === 4) {
|
||||
return v4.readNotebook(<any>contents);
|
||||
} else if (contents.nbformat === 3) {
|
||||
return v3.readNotebook(<any>contents);
|
||||
}
|
||||
if (contents.nbformat) {
|
||||
throw new TypeError(localize('nbformatNotRecognized', "nbformat v{0}.{1} not recognized", contents.nbformat as any, contents.nbformat_minor as any));
|
||||
}
|
||||
}
|
||||
|
||||
// else, fallthrough condition
|
||||
throw new TypeError(localize('nbNotSupported', "This file does not have a valid notebook format"));
|
||||
|
||||
}
|
||||
|
||||
public async save(notebookUri: URI, notebook: nb.INotebookContents): Promise<nb.INotebookContents> {
|
||||
public async serializeNotebook(notebook: nb.INotebookContents): Promise<string> {
|
||||
// Convert to JSON with pretty-print functionality
|
||||
let contents = JSON.stringify(notebook, undefined, ' ');
|
||||
await this.fileService.writeFile(notebookUri, VSBuffer.fromString(contents));
|
||||
return notebook;
|
||||
return contents;
|
||||
}
|
||||
|
||||
private parseFromJson(contentString: string): JSONObject {
|
||||
|
||||
@@ -4,24 +4,26 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IJSONSchema } from 'vs/base/common/jsonSchema';
|
||||
import { ExtensionsRegistry, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { localize } from 'vs/nls';
|
||||
import * as platform from 'vs/platform/registry/common/platform';
|
||||
import * as azdata from 'azdata';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
|
||||
export const NotebookProviderRegistryId = 'notebooks.providers.registry';
|
||||
|
||||
export const Extensions = {
|
||||
NotebookProviderContribution: 'notebook.providers',
|
||||
NotebookProviderDescriptionContribution: 'notebook.providers',
|
||||
NotebookLanguageMagicContribution: 'notebook.languagemagics'
|
||||
};
|
||||
|
||||
export interface NotebookProviderRegistration {
|
||||
export interface ProviderDescriptionRegistration {
|
||||
provider: string;
|
||||
fileExtensions: string | string[];
|
||||
standardKernels: azdata.nb.IStandardKernel | azdata.nb.IStandardKernel[];
|
||||
}
|
||||
|
||||
let notebookProviderType: IJSONSchema = {
|
||||
let providerDescriptionType: IJSONSchema = {
|
||||
type: 'object',
|
||||
default: { provider: '', fileExtensions: [], standardKernels: [] },
|
||||
properties: {
|
||||
@@ -86,13 +88,13 @@ let notebookProviderType: IJSONSchema = {
|
||||
}
|
||||
};
|
||||
|
||||
let notebookContrib: IJSONSchema = {
|
||||
description: localize('vscode.extension.contributes.notebook.providers', "Contributes notebook providers."),
|
||||
let providerDescriptionContrib: IJSONSchema = {
|
||||
description: localize('vscode.extension.contributes.notebook.providersDescriptions', "Contributes notebook provider descriptions."),
|
||||
oneOf: [
|
||||
notebookProviderType,
|
||||
providerDescriptionType,
|
||||
{
|
||||
type: 'array',
|
||||
items: notebookProviderType
|
||||
items: providerDescriptionType
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -146,81 +148,69 @@ export interface NotebookLanguageMagicRegistration {
|
||||
}
|
||||
|
||||
export interface INotebookProviderRegistry {
|
||||
readonly providers: NotebookProviderRegistration[];
|
||||
readonly providerDescriptions: ProviderDescriptionRegistration[];
|
||||
readonly languageMagics: NotebookLanguageMagicRegistration[];
|
||||
readonly onNewRegistration: Event<{ id: string, registration: NotebookProviderRegistration }>;
|
||||
|
||||
registerNotebookProvider(provider: NotebookProviderRegistration): void;
|
||||
readonly onNewDescriptionRegistration: Event<{ id: string, registration: ProviderDescriptionRegistration }>;
|
||||
|
||||
registerProviderDescription(provider: ProviderDescriptionRegistration): void;
|
||||
registerNotebookLanguageMagic(magic: NotebookLanguageMagicRegistration): void;
|
||||
}
|
||||
|
||||
class NotebookProviderRegistry implements INotebookProviderRegistry {
|
||||
private providerIdToRegistration = new Map<string, NotebookProviderRegistration>();
|
||||
private magicToRegistration = new Map<string, NotebookLanguageMagicRegistration>();
|
||||
private _onNewRegistration = new Emitter<{ id: string, registration: NotebookProviderRegistration }>();
|
||||
public readonly onNewRegistration: Event<{ id: string, registration: NotebookProviderRegistration }> = this._onNewRegistration.event;
|
||||
private _providerDescriptionRegistration = new Map<string, ProviderDescriptionRegistration>();
|
||||
private _magicToRegistration = new Map<string, NotebookLanguageMagicRegistration>();
|
||||
|
||||
registerNotebookProvider(registration: NotebookProviderRegistration): void {
|
||||
// Note: this method intentionally overrides default provider for a file type.
|
||||
// This means that any built-in provider will be overridden by registered extensions
|
||||
this.providerIdToRegistration.set(registration.provider, registration);
|
||||
this._onNewRegistration.fire({ id: registration.provider, registration: registration });
|
||||
private _onNewDescriptionRegistration = new Emitter<{ id: string, registration: ProviderDescriptionRegistration }>();
|
||||
public readonly onNewDescriptionRegistration: Event<{ id: string, registration: ProviderDescriptionRegistration }> = this._onNewDescriptionRegistration.event;
|
||||
|
||||
registerProviderDescription(registration: ProviderDescriptionRegistration): void {
|
||||
this._providerDescriptionRegistration.set(registration.provider, registration);
|
||||
this._onNewDescriptionRegistration.fire({ id: registration.provider, registration: registration });
|
||||
}
|
||||
|
||||
public get providers(): NotebookProviderRegistration[] {
|
||||
let registrationArray: NotebookProviderRegistration[] = [];
|
||||
this.providerIdToRegistration.forEach(p => registrationArray.push(p));
|
||||
public get providerDescriptions(): ProviderDescriptionRegistration[] {
|
||||
let registrationArray: ProviderDescriptionRegistration[] = [];
|
||||
this._providerDescriptionRegistration.forEach(p => registrationArray.push(p));
|
||||
return registrationArray;
|
||||
}
|
||||
|
||||
registerNotebookLanguageMagic(magicRegistration: NotebookLanguageMagicRegistration): void {
|
||||
this.magicToRegistration.set(magicRegistration.magic, magicRegistration);
|
||||
this._magicToRegistration.set(magicRegistration.magic, magicRegistration);
|
||||
}
|
||||
|
||||
public get languageMagics(): NotebookLanguageMagicRegistration[] {
|
||||
let registrationArray: NotebookLanguageMagicRegistration[] = [];
|
||||
this.magicToRegistration.forEach(p => registrationArray.push(p));
|
||||
this._magicToRegistration.forEach(p => registrationArray.push(p));
|
||||
return registrationArray;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const notebookProviderRegistry = new NotebookProviderRegistry();
|
||||
platform.Registry.add(Extensions.NotebookProviderContribution, notebookProviderRegistry);
|
||||
|
||||
|
||||
ExtensionsRegistry.registerExtensionPoint<NotebookProviderRegistration | NotebookProviderRegistration[]>({ extensionPoint: Extensions.NotebookProviderContribution, jsonSchema: notebookContrib }).setHandler(extensions => {
|
||||
|
||||
function handleExtension(contrib: NotebookProviderRegistration, extension: IExtensionPointUser<any>) {
|
||||
notebookProviderRegistry.registerNotebookProvider(contrib);
|
||||
}
|
||||
platform.Registry.add(NotebookProviderRegistryId, notebookProviderRegistry);
|
||||
|
||||
ExtensionsRegistry.registerExtensionPoint<ProviderDescriptionRegistration | ProviderDescriptionRegistration[]>({ extensionPoint: Extensions.NotebookProviderDescriptionContribution, jsonSchema: providerDescriptionContrib }).setHandler(extensions => {
|
||||
for (let extension of extensions) {
|
||||
const { value } = extension;
|
||||
if (Array.isArray(value)) {
|
||||
for (let command of value) {
|
||||
handleExtension(command, extension);
|
||||
notebookProviderRegistry.registerProviderDescription(command);
|
||||
}
|
||||
} else {
|
||||
handleExtension(value, extension);
|
||||
notebookProviderRegistry.registerProviderDescription(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ExtensionsRegistry.registerExtensionPoint<NotebookLanguageMagicRegistration | NotebookLanguageMagicRegistration[]>({ extensionPoint: Extensions.NotebookLanguageMagicContribution, jsonSchema: languageMagicContrib }).setHandler(extensions => {
|
||||
|
||||
function handleExtension(contrib: NotebookLanguageMagicRegistration, extension: IExtensionPointUser<any>) {
|
||||
notebookProviderRegistry.registerNotebookLanguageMagic(contrib);
|
||||
}
|
||||
|
||||
for (let extension of extensions) {
|
||||
const { value } = extension;
|
||||
if (Array.isArray(value)) {
|
||||
for (let command of value) {
|
||||
handleExtension(command, extension);
|
||||
notebookProviderRegistry.registerNotebookLanguageMagic(command);
|
||||
}
|
||||
} else {
|
||||
handleExtension(value, extension);
|
||||
notebookProviderRegistry.registerNotebookLanguageMagic(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user