diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index bb478031e84..d4f5348dbe5 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -168,7 +168,8 @@ class DocumentAndEditorState { @extHostNamedCustomer(MainContext.MainThreadNotebook) export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape { - private readonly _notebookProviders = new Map(); + static mainthreadNotebookDocumentHandle: number = 0; + private readonly _notebookProviders = new Map(); private readonly _notebookKernels = new Map(); private readonly _notebookKernelProviders = new Map, provider: IDisposable }>(); private readonly _notebookRenderers = new Map(); @@ -203,7 +204,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo createNotebookTextModelAndBindListeners(uri: URI, viewType: string, supportBackup: boolean) { const disposableStore = new DisposableStore(); - const textModel = this._instantiationService.createInstance(NotebookTextModel, MainThreadNotebookController.documentHandle++, viewType, supportBackup, uri); + const textModel = this._instantiationService.createInstance(NotebookTextModel, MainThreadNotebooks.mainthreadNotebookDocumentHandle++, viewType, supportBackup, uri); disposableStore.add(textModel.onDidModelChangeProxy(e => { this._proxy.$acceptModelChanged(textModel.uri, e); this._proxy.$acceptEditorPropertiesChanged(uri, { selections: { selections: textModel.selections }, metadata: null }); @@ -437,10 +438,81 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo this._notebookService.unregisterNotebookRenderer(id); } - async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernel: INotebookKernelInfoDto | undefined): Promise { - let controller = new MainThreadNotebookController(this._proxy, this, viewType, supportBackup, kernel, this._notebookService, this._instantiationService); - this._notebookProviders.set(viewType, controller); - this._notebookService.registerNotebookController(viewType, extension, controller); + async $registerNotebookProvider(_extension: NotebookExtensionDescription, _viewType: string, _supportBackup: boolean, _kernel: INotebookKernelInfoDto | undefined): Promise { + const controller: IMainNotebookController = { + kernel: _kernel, + reloadNotebook: async (mainthreadTextModel: NotebookTextModel) => { + const data = await this._proxy.$resolveNotebookData(_viewType, mainthreadTextModel.uri); + if (!data) { + return; + } + + mainthreadTextModel.languages = data.languages; + mainthreadTextModel.metadata = data.metadata; + + const edits: ICellEditOperation[] = [ + { editType: CellEditType.Delete, count: mainthreadTextModel.cells.length, index: 0 }, + { editType: CellEditType.Insert, index: 0, cells: data.cells } + ]; + + await this._notebookService.transformEditsOutputs(mainthreadTextModel, edits); + await new Promise(resolve => { + DOM.scheduleAtNextAnimationFrame(() => { + const ret = mainthreadTextModel!.$applyEdit(mainthreadTextModel!.versionId, edits, true); + resolve(ret); + }); + }); + }, + createNotebook: async (viewType: string, uri: URI, editorId?: string, backupId?: string) => { + const textModel = this.createNotebookTextModelAndBindListeners(uri, viewType, _supportBackup); + // open notebook document + const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId); + if (!data) { + return; + } + + textModel.languages = data.languages; + textModel.metadata = data.metadata; + + if (data.cells.length) { + textModel.initialize(data!.cells); + } else { + const mainCell = textModel.createCellTextModel([''], textModel.languages.length ? textModel.languages[0] : '', CellKind.Code, [], undefined); + textModel.insertTemplateCell(mainCell); + } + + this._proxy.$acceptEditorPropertiesChanged(uri, { selections: null, metadata: textModel.metadata }); + + return textModel; + }, + resolveNotebookEditor: async (viewType: string, uri: URI, editorId: string) => { + await this._proxy.$resolveNotebookEditor(viewType, uri, editorId); + }, + executeNotebookByAttachedKernel: async (viewType: string, uri: URI, token: CancellationToken) => { + return this.executeNotebookByAttachedKernel(viewType, uri, token); + }, + onDidReceiveMessage: (editorId: string, rendererType: string | undefined, message: unknown) => { + this._proxy.$onDidReceiveMessage(editorId, rendererType, message); + }, + removeNotebookDocument: async (uri: URI) => { + return this.removeNotebookTextModel(uri); + }, + executeNotebookCell: async (uri: URI, handle: number, token: CancellationToken) => { + return this._proxy.$executeNotebookByAttachedKernel(_viewType, uri, handle, token); + }, + save: async (uri: URI, token: CancellationToken) => { + return this._proxy.$saveNotebook(_viewType, uri, token); + }, + saveAs: async (uri: URI, target: URI, token: CancellationToken) => { + return this._proxy.$saveNotebookAs(_viewType, uri, target, token); + }, + backup: async (uri: URI, token: CancellationToken) => { + return this._proxy.$backup(_viewType, uri, token); + } + }; + + this._notebookProviders.set(_viewType, controller); + this._notebookService.registerNotebookController(_viewType, _extension, controller); return; } @@ -571,106 +643,6 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo } } -export class MainThreadNotebookController implements IMainNotebookController { - static documentHandle: number = 0; - - constructor( - private readonly _proxy: ExtHostNotebookShape, - private _mainThreadNotebook: MainThreadNotebooks, - private _viewType: string, - private _supportBackup: boolean, - readonly kernel: INotebookKernelInfoDto | undefined, - readonly notebookService: INotebookService, - readonly _instantiationService: IInstantiationService - - ) { - } - - async createNotebook(viewType: string, uri: URI, forceReload: boolean, editorId?: string, backupId?: string): Promise { - let mainthreadTextModel = this.notebookService.getNotebookTextModel(uri); - - if (mainthreadTextModel) { - if (forceReload) { - const data = await this._proxy.$resolveNotebookData(viewType, uri); - if (!data) { - return; - } - - mainthreadTextModel.languages = data.languages; - mainthreadTextModel.metadata = data.metadata; - - const edits: ICellEditOperation[] = [ - { editType: CellEditType.Delete, count: mainthreadTextModel.cells.length, index: 0 }, - { editType: CellEditType.Insert, index: 0, cells: data.cells } - ]; - - await this.notebookService.transformEditsOutputs(mainthreadTextModel, edits); - await new Promise(resolve => { - DOM.scheduleAtNextAnimationFrame(() => { - const ret = mainthreadTextModel!.$applyEdit(mainthreadTextModel!.versionId, edits, true); - resolve(ret); - }); - }); - } - return mainthreadTextModel; - } - - const textModel = this._mainThreadNotebook.createNotebookTextModelAndBindListeners(uri, viewType, this._supportBackup); - // open notebook document - const data = await this._proxy.$resolveNotebookData(viewType, uri, backupId); - if (!data) { - return; - } - - textModel.languages = data.languages; - textModel.metadata = data.metadata; - - if (data.cells.length) { - textModel.initialize(data!.cells); - } else { - const mainCell = textModel.createCellTextModel([''], textModel.languages.length ? textModel.languages[0] : '', CellKind.Code, [], undefined); - textModel.insertTemplateCell(mainCell); - } - - this._proxy.$acceptEditorPropertiesChanged(uri, { selections: null, metadata: textModel.metadata }); - - return textModel; - } - - async resolveNotebookEditor(viewType: string, uri: URI, editorId: string) { - await this._proxy.$resolveNotebookEditor(viewType, uri, editorId); - } - - async executeNotebookByAttachedKernel(viewType: string, uri: URI, token: CancellationToken): Promise { - return this._mainThreadNotebook.executeNotebookByAttachedKernel(viewType, uri, token); - } - - onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: unknown): void { - this._proxy.$onDidReceiveMessage(editorId, rendererType, message); - } - - async removeNotebookDocument(uri: URI): Promise { - return this._mainThreadNotebook.removeNotebookTextModel(uri); - } - - async executeNotebookCell(uri: URI, handle: number, token: CancellationToken): Promise { - return this._proxy.$executeNotebookByAttachedKernel(this._viewType, uri, handle, token); - } - - async save(uri: URI, token: CancellationToken): Promise { - return this._proxy.$saveNotebook(this._viewType, uri, token); - } - - async saveAs(uri: URI, target: URI, token: CancellationToken): Promise { - return this._proxy.$saveNotebookAs(this._viewType, uri, target, token); - } - - async backup(uri: URI, token: CancellationToken): Promise { - const backupId = await this._proxy.$backup(this._viewType, uri, token); - return backupId; - } -} - export class MainThreadNotebookKernel implements INotebookKernelInfo { constructor( private readonly _proxy: ExtHostNotebookShape, diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 0f330860978..1035b10c7f1 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -399,13 +399,24 @@ export class NotebookService extends Disposable implements INotebookService, ICu return undefined; } - const notebookModel = await provider.controller.createNotebook(viewType, uri, forceReload, editorId, backupId); - if (!notebookModel) { - return undefined; + const modelId = MODEL_ID(uri); + + let notebookModel: NotebookTextModel | undefined = undefined; + if (this._models.has(modelId)) { + // the model already exists + notebookModel = this._models.get(modelId)!.model; + if (forceReload) { + await provider.controller.reloadNotebook(notebookModel); + } + } else { + notebookModel = await provider.controller.createNotebook(viewType, uri, editorId, backupId); + + if (!notebookModel) { + return undefined; + } } // new notebook model created - const modelId = MODEL_ID(uri); const modelData = new ModelData( notebookModel!, (model) => this._onWillDisposeDocument(model), diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index 4e89983b992..1a7783fe4ea 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -22,7 +22,8 @@ export const INotebookService = createDecorator('notebookServi export interface IMainNotebookController { kernel: INotebookKernelInfoDto | undefined; - createNotebook(viewType: string, uri: URI, forceReload: boolean, editorId?: string, backupId?: string): Promise; + createNotebook(viewType: string, uri: URI, editorId?: string, backupId?: string): Promise; + reloadNotebook(mainthreadTextModel: NotebookTextModel): Promise; resolveNotebookEditor(viewType: string, uri: URI, editorId: string): Promise; executeNotebookByAttachedKernel(viewType: string, uri: URI, token: CancellationToken): Promise; onDidReceiveMessage(editorId: string, rendererType: string | undefined, message: any): void;