diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 12242914859..6f2566049d7 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -4,12 +4,12 @@ *--------------------------------------------------------------------------------------------*/ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; -import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, NotebookCellsSplice, NotebookCellOutputsSplice } from '../common/extHost.protocol'; +import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext, NotebookCellOutputsSplice } from '../common/extHost.protocol'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { URI, UriComponents } from 'vs/base/common/uri'; import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { Emitter, Event } from 'vs/base/common/event'; -import { ICell, IOutput, INotebook, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { ICell, IOutput, INotebook, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export class MainThreadCell implements ICell { @@ -76,8 +76,8 @@ export class MainThreadCell implements ICell { export class MainThreadNotebookDocument extends Disposable implements INotebook { private readonly _onWillDispose: Emitter = this._register(new Emitter()); readonly onWillDispose: Event = this._onWillDispose.event; - private readonly _onDidChangeCells = new Emitter(); - get onDidChangeCells(): Event { return this._onDidChangeCells.event; } + private readonly _onDidChangeCells = new Emitter(); + get onDidChangeCells(): Event { return this._onDidChangeCells.event; } private _onDidChangeDirtyState = new Emitter(); onDidChangeDirtyState: Event = this._onDidChangeDirtyState.event; private _mapping: Map = new Map(); @@ -181,8 +181,7 @@ export class MainThreadNotebookDocument extends Disposable implements INotebook this.cells.splice(splice[0], splice[1], ...newCells); }); - // @TODO, support incremental insertion/deletion instead of simple list relayout. - this._onDidChangeCells.fire(); + this._onDidChangeCells.fire(splices); } spliceNotebookCellOutputs(cellHandle: number, splices: NotebookCellOutputsSplice[]): void { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 3d53700815b..a83ea7ce029 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -29,7 +29,7 @@ import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/output/out import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/renderers/backLayerWebView'; import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/renderers/cellRenderer'; import { CellViewModel } from 'vs/workbench/contrib/notebook/browser/renderers/cellViewModel'; -import { CELL_MARGIN, INotebook } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CELL_MARGIN, INotebook, NotebookCellsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -287,8 +287,8 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { } this.model = model; - this.localStore.add(this.model.onDidChangeCells(() => { - this.updateViewCells(); + this.localStore.add(this.model.onDidChangeCells((e) => { + this.updateViewCells(e); })); let viewState = this.loadTextEditorViewState(input); @@ -402,7 +402,13 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { } } - updateViewCells() { + updateViewCells(splices: NotebookCellsSplice[]) { + let update = () => splices.reverse().forEach((diff) => { + this.list?.splice(diff[0], diff[1], diff[2].map(cell => { + return this.instantiationService.createInstance(CellViewModel, this.viewType!, this.notebook!.handle, cell, false); + })); + }); + if (this.list?.view.isRendering) { if (this.relayoutDisposable) { this.relayoutDisposable.dispose(); @@ -410,11 +416,11 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { } this.relayoutDisposable = DOM.scheduleAtNextAnimationFrame(() => { - this.list?.rerender(); + update(); this.relayoutDisposable = null; }); } else { - this.list?.rerender(); + update(); } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts index ca5255b9ed7..b892f60dcb4 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorInput.ts @@ -8,7 +8,7 @@ import { ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextModel } from 'vs/editor/common/model'; import { Emitter, Event } from 'vs/base/common/event'; import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; -import { INotebook, ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebook, ICell, NotebookCellsSplice } from 'vs/workbench/contrib/notebook/common/notebookCommon'; export class NotebookEditorModel extends EditorModel { private _dirty = false; @@ -16,8 +16,8 @@ export class NotebookEditorModel extends EditorModel { protected readonly _onDidChangeDirty = this._register(new Emitter()); readonly onDidChangeDirty = this._onDidChangeDirty.event; - private readonly _onDidChangeCells = new Emitter(); - get onDidChangeCells(): Event { return this._onDidChangeCells.event; } + private readonly _onDidChangeCells = new Emitter(); + get onDidChangeCells(): Event { return this._onDidChangeCells.event; } constructor( public readonly textModel: ITextModel, @@ -32,8 +32,8 @@ export class NotebookEditorModel extends EditorModel { this._onDidChangeDirty.fire(); } })); - this._register(_notebook.onDidChangeCells(() => { - this._onDidChangeCells.fire(); + this._register(_notebook.onDidChangeCells((e) => { + this._onDidChangeCells.fire(e); })); } } diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index 0160a2ff934..e44f65feedb 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -129,7 +129,7 @@ export interface INotebook { languages: string[]; cells: ICell[]; renderers: Set; - onDidChangeCells?: Event; + onDidChangeCells?: Event; onDidChangeDirtyState: Event; onWillDispose(listener: () => void): IDisposable; save(): Promise; @@ -152,3 +152,9 @@ export interface IOutputTransformContribution { export const CELL_MARGIN = 24; + +export type NotebookCellsSplice = [ + number /* start */, + number /* delete count */, + ICell[] +];