Add option to use notebook json contents instead of file string when creating a notebook. (#18972)

This commit is contained in:
Cory Rivera
2022-04-08 16:39:14 -07:00
committed by GitHub
parent 828c6760e2
commit c2cc32a4a0
4 changed files with 44 additions and 19 deletions

View File

@@ -1009,7 +1009,7 @@ export interface INotebookShowOptions {
providerId?: string; providerId?: string;
connectionProfile?: azdata.IConnectionProfile; connectionProfile?: azdata.IConnectionProfile;
defaultKernel?: azdata.nb.IKernelSpec; defaultKernel?: azdata.nb.IKernelSpec;
initialContent?: string; initialContent?: string | azdata.nb.INotebookContents;
initialDirtyState?: boolean; initialDirtyState?: boolean;
} }

View File

@@ -222,6 +222,7 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
private _providers: string[]; private _providers: string[];
private _standardKernels: IStandardKernelWithProvider[]; private _standardKernels: IStandardKernelWithProvider[];
private _connectionProfile: IConnectionProfile; private _connectionProfile: IConnectionProfile;
private _notebookContents: azdata.nb.INotebookContents;
private _defaultKernel: azdata.nb.IKernelSpec; private _defaultKernel: azdata.nb.IKernelSpec;
public hasBootstrapped = false; public hasBootstrapped = false;
// Holds the HTML content for the editor when the editor discards this input and loads another // Holds the HTML content for the editor when the editor discards this input and loads another
@@ -283,7 +284,7 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
public get contentLoader(): IContentLoader { public get contentLoader(): IContentLoader {
if (!this._contentLoader) { if (!this._contentLoader) {
let contentManager = this.instantiationService.createInstance(LocalContentManager); let contentManager = this.instantiationService.createInstance(LocalContentManager);
this._contentLoader = this.instantiationService.createInstance(NotebookEditorContentLoader, this, contentManager); this._contentLoader = this.instantiationService.createInstance(NotebookEditorContentLoader, this, contentManager, this._notebookContents);
} }
return this._contentLoader; return this._contentLoader;
} }
@@ -319,6 +320,11 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
return this._connectionProfile; return this._connectionProfile;
} }
public setNotebookContents(value: azdata.nb.INotebookContents) {
this._notebookContents = value;
(this.contentLoader as NotebookEditorContentLoader).notebookContents = value;
}
public get standardKernels(): IStandardKernelWithProvider[] { public get standardKernels(): IStandardKernelWithProvider[] {
return this._standardKernels; return this._standardKernels;
} }
@@ -461,7 +467,7 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
this._standardKernels.push(...standardKernels); this._standardKernels.push(...standardKernels);
} }
let serializationProvider = await this.notebookService.getOrCreateSerializationManager(this._providerId, this._resource); let serializationProvider = await this.notebookService.getOrCreateSerializationManager(this._providerId, this._resource);
this._contentLoader = this.instantiationService.createInstance(NotebookEditorContentLoader, this, serializationProvider.contentManager); this._contentLoader = this.instantiationService.createInstance(NotebookEditorContentLoader, this, serializationProvider.contentManager, this._notebookContents);
} }
} }
@@ -541,12 +547,18 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
export class NotebookEditorContentLoader implements IContentLoader { export class NotebookEditorContentLoader implements IContentLoader {
constructor( constructor(
private notebookInput: NotebookInput, private notebookInput: NotebookInput,
private contentManager: azdata.nb.ContentManager) { private contentManager: azdata.nb.ContentManager,
public notebookContents: azdata.nb.INotebookContents | undefined) {
} }
async loadContent(): Promise<azdata.nb.INotebookContents> { async loadContent(): Promise<azdata.nb.INotebookContents> {
let notebookContents: azdata.nb.INotebookContents;
if (this.notebookContents) {
notebookContents = this.notebookContents;
} else {
let notebookEditorModel = await this.notebookInput.resolve(); let notebookEditorModel = await this.notebookInput.resolve();
let notebookContents = await this.contentManager.deserializeNotebook(notebookEditorModel.contentString); notebookContents = await this.contentManager.deserializeNotebook(notebookEditorModel.contentString);
}
// Special case .NET Interactive kernel spec to handle inconsistencies between notebook providers and jupyter kernel specs // Special case .NET Interactive kernel spec to handle inconsistencies between notebook providers and jupyter kernel specs
if (notebookContents.metadata?.kernelspec?.display_name?.startsWith(DotnetInteractiveJupyterLabelPrefix)) { if (notebookContents.metadata?.kernelspec?.display_name?.startsWith(DotnetInteractiveJupyterLabelPrefix)) {

View File

@@ -10,8 +10,9 @@ import { IStandardKernelWithProvider } from 'sql/workbench/services/notebook/bro
import { IEditorInput } from 'vs/workbench/common/editor'; import { IEditorInput } from 'vs/workbench/common/editor';
export interface INotebookInput extends IEditorInput { export interface INotebookInput extends IEditorInput {
defaultKernel?: azdata.nb.IKernelSpec, defaultKernel?: azdata.nb.IKernelSpec;
connectionProfile?: azdata.IConnectionProfile, connectionProfile?: azdata.IConnectionProfile;
setNotebookContents(contents: azdata.nb.INotebookContents): void;
isDirty(): boolean; isDirty(): boolean;
setDirty(boolean); setDirty(boolean);
readonly notebookUri: URI; readonly notebookUri: URI;

View File

@@ -185,6 +185,7 @@ export class NotebookService extends Disposable implements INotebookService {
private _trustedCacheQueue: URI[] = []; private _trustedCacheQueue: URI[] = [];
private _unTrustedCacheQueue: URI[] = []; private _unTrustedCacheQueue: URI[] = [];
private _onCodeCellExecutionStart: Emitter<void> = new Emitter<void>(); private _onCodeCellExecutionStart: Emitter<void> = new Emitter<void>();
private _notebookInputsMap: Map<string, IEditorInput> = new Map();
constructor( constructor(
@ILifecycleService lifecycleService: ILifecycleService, @ILifecycleService lifecycleService: ILifecycleService,
@@ -255,7 +256,7 @@ export class NotebookService extends Disposable implements INotebookService {
do { do {
uri = URI.from({ scheme: Schemas.untitled, path: `Notebook-${counter}` }); uri = URI.from({ scheme: Schemas.untitled, path: `Notebook-${counter}` });
counter++; counter++;
} while (this._untitledEditorService.get(uri)); } while (this._untitledEditorService.get(uri) || this._notebookInputsMap.has(uri.toString())); // Also have to check stored inputs, since those might not be opened in an editor yet.
return uri; return uri;
} }
@@ -268,16 +269,9 @@ export class NotebookService extends Disposable implements INotebookService {
resource = uri; resource = uri;
} }
let serializedContent: string;
if (contents) {
// Have to serialize contents again first, since our notebook code assumes input is based on the raw file contents
let manager = await this.getOrCreateSerializationManager(providerId, uri);
serializedContent = await manager.contentManager.serializeNotebook(contents);
}
let options: INotebookShowOptions = { let options: INotebookShowOptions = {
providerId: providerId, providerId: providerId,
initialContent: serializedContent initialContent: contents
}; };
return this.createNotebookInput(options, resource); return this.createNotebookInput(options, resource);
} }
@@ -286,6 +280,9 @@ export class NotebookService extends Disposable implements INotebookService {
let uri: URI; let uri: URI;
if (resource) { if (resource) {
uri = URI.revive(resource); uri = URI.revive(resource);
if (this._notebookInputsMap.has(uri.toString())) {
return this._notebookInputsMap.get(uri.toString());
}
} else { } else {
uri = this.getUntitledFileUri(); uri = this.getUntitledFileUri();
} }
@@ -293,12 +290,21 @@ export class NotebookService extends Disposable implements INotebookService {
let fileInput: IEditorInput; let fileInput: IEditorInput;
let languageMode = options.providerId === INTERACTIVE_PROVIDER_ID ? INTERACTIVE_LANGUAGE_MODE : DEFAULT_NB_LANGUAGE_MODE; let languageMode = options.providerId === INTERACTIVE_PROVIDER_ID ? INTERACTIVE_LANGUAGE_MODE : DEFAULT_NB_LANGUAGE_MODE;
let initialStringContents: string;
if (options.initialContent) {
if (typeof options.initialContent === 'string') {
initialStringContents = options.initialContent;
} else {
let manager = await this.getOrCreateSerializationManager(options.providerId, uri);
initialStringContents = await manager.contentManager.serializeNotebook(options.initialContent);
}
}
if (isUntitled && path.isAbsolute(uri.fsPath)) { if (isUntitled && path.isAbsolute(uri.fsPath)) {
const model = this._untitledEditorService.create({ associatedResource: uri, mode: languageMode, initialValue: options.initialContent }); const model = this._untitledEditorService.create({ associatedResource: uri, mode: languageMode, initialValue: initialStringContents });
fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model); fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
} else { } else {
if (isUntitled) { if (isUntitled) {
const model = this._untitledEditorService.create({ untitledResource: uri, mode: languageMode, initialValue: options.initialContent }); const model = this._untitledEditorService.create({ untitledResource: uri, mode: languageMode, initialValue: initialStringContents });
fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model); fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
} else { } else {
fileInput = this._editorService.createEditorInput({ forceFile: true, resource: uri, mode: languageMode }); fileInput = this._editorService.createEditorInput({ forceFile: true, resource: uri, mode: languageMode });
@@ -312,6 +318,9 @@ export class NotebookService extends Disposable implements INotebookService {
if (isINotebookInput(fileInput)) { if (isINotebookInput(fileInput)) {
fileInput.defaultKernel = options.defaultKernel; fileInput.defaultKernel = options.defaultKernel;
fileInput.connectionProfile = options.connectionProfile; fileInput.connectionProfile = options.connectionProfile;
if (typeof options.initialContent !== 'string') {
fileInput.setNotebookContents(options.initialContent);
}
if (isUntitled) { if (isUntitled) {
let untitledModel = await fileInput.resolve(); let untitledModel = await fileInput.resolve();
@@ -327,6 +336,7 @@ export class NotebookService extends Disposable implements INotebookService {
throw new Error(localize('failedToCreateNotebookInput', "Failed to create notebook input for provider '{0}'", options.providerId)); throw new Error(localize('failedToCreateNotebookInput', "Failed to create notebook input for provider '{0}'", options.providerId));
} }
this._notebookInputsMap.set(uri.toString(), fileInput);
return fileInput; return fileInput;
} }
@@ -616,6 +626,8 @@ export class NotebookService extends Disposable implements INotebookService {
if (this._editors.delete(editor.id)) { if (this._editors.delete(editor.id)) {
this._onNotebookEditorRemove.fire(editor); this._onNotebookEditorRemove.fire(editor);
} }
this._notebookInputsMap.delete(editor.notebookParams.notebookUri.toString());
// Remove the manager from the tracked list, and let the notebook provider know that it should update its mappings // Remove the manager from the tracked list, and let the notebook provider know that it should update its mappings
this.sendNotebookCloseToProvider(editor); this.sendNotebookCloseToProvider(editor);
} }