diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 1b98220afd5..7b44dcc0123 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1325,7 +1325,7 @@ declare module 'vscode' { readonly viewType: string; readonly isDirty: boolean; readonly isUntitled: boolean; - readonly cells: NotebookCell[]; + readonly cells: ReadonlyArray; languages: string[]; displayOrder?: GlobPattern[]; metadata: NotebookDocumentMetadata; diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index 9325f9ae912..b7d99e7e7a8 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -58,7 +58,7 @@ interface INotebookEventEmitter { const addIdToOutput = (output: IRawOutput, id = UUID.generateUuid()): IProcessedOutput => output.outputKind === CellOutputKind.Rich ? ({ ...output, outputId: id }) : output; -export class ExtHostCell extends Disposable implements vscode.NotebookCell { +export class ExtHostCell extends Disposable { public static asModelAddData(notebook: ExtHostNotebookDocument, cell: IMainCellDto): IExtHostModelAddedData { return { @@ -85,49 +85,56 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell { readonly uri: URI; readonly cellKind: CellKind; - private _document: vscode.TextDocument | undefined; + private _cell: vscode.NotebookCell | undefined; constructor( - private _proxy: MainThreadNotebookShape, - readonly notebook: ExtHostNotebookDocument, - private _extHostDocument: ExtHostDocumentsAndEditors, - cell: IMainCellDto, + private readonly _proxy: MainThreadNotebookShape, + private readonly _notebook: ExtHostNotebookDocument, + private readonly _extHostDocument: ExtHostDocumentsAndEditors, + private readonly _cellData: IMainCellDto, ) { super(); - this.handle = cell.handle; - this.uri = URI.revive(cell.uri); - this.cellKind = cell.cellKind; + this.handle = _cellData.handle; + this.uri = URI.revive(_cellData.uri); + this.cellKind = _cellData.cellKind; - this._outputs = cell.outputs; + this._outputs = _cellData.outputs; for (const output of this._outputs) { this._outputMapping.set(output, output.outputId); delete output.outputId; } - const observableMetadata = getObservable(cell.metadata ?? {}); + const observableMetadata = getObservable(_cellData.metadata ?? {}); this._metadata = observableMetadata.proxy; this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => { this._updateMetadata(); })); } - get document(): vscode.TextDocument { - if (!this._document) { - this._document = this._extHostDocument.getDocument(this.uri)?.document; + get cell(): vscode.NotebookCell { + if (!this._cell) { + const that = this; + const document = this._extHostDocument.getDocument(this.uri)!.document; + this._cell = Object.freeze({ + notebook: that._notebook, + uri: that.uri, + cellKind: this._cellData.cellKind, + document, + language: document.languageId, + get outputs() { return that._outputs; }, + set outputs(value) { that._updateOutputs(value); }, + get metadata() { return that._metadata; }, + set metadata(value) { + that.setMetadata(value); + that._updateMetadata(); + }, + }); } - return this._document!; + return this._cell; } - get language(): string { - return this.document.languageId; - } - - get outputs() { - return this._outputs; - } - - set outputs(newOutputs: vscode.CellOutput[]) { + private _updateOutputs(newOutputs: vscode.CellOutput[]) { const rawDiffs = diff(this._outputs || [], newOutputs || [], (a) => { return this._outputMapping.has(a); }); @@ -157,15 +164,6 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell { this._onDidChangeOutputs.fire(transformedDiffs); } - get metadata() { - return this._metadata; - } - - set metadata(newMetadata: vscode.NotebookCellMetadata) { - this.setMetadata(newMetadata); - this._updateMetadata(); - } - setMetadata(newMetadata: vscode.NotebookCellMetadata): void { // Don't apply metadata defaults here, 'undefined' means 'inherit from document metadata' this._metadataChangeListener.dispose(); @@ -177,7 +175,21 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell { } private _updateMetadata(): Promise { - return this._proxy.$updateNotebookCellMetadata(this.notebook.viewType, this.notebook.uri, this.handle, this._metadata); + return this._proxy.$updateNotebookCellMetadata(this._notebook.viewType, this._notebook.uri, this.handle, this._metadata); + } +} + +class RawContentChangeEvent { + + constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: ExtHostCell[], readonly items: ExtHostCell[]) { } + + static asApiEvent(event: RawContentChangeEvent): vscode.NotebookCellsChangeData { + return Object.freeze({ + start: event.start, + deletedCount: event.deletedCount, + deletedItems: event.deletedItems.map(data => data.cell), + items: event.items.map(data => data.cell) + }); } } @@ -189,8 +201,8 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo private _cellDisposableMapping = new Map(); - get cells() { - return this._cells; + get cells(): ReadonlyArray { + return this._cells.map(cellData => cellData.cell); } private _languages: string[] = []; @@ -367,7 +379,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo return; } - const contentChangeEvents: vscode.NotebookCellsChangeData[] = []; + const contentChangeEvents: RawContentChangeEvent[] = []; const addedCellDocuments: IExtHostModelAddedData[] = []; const removedCellDocuments: URI[] = []; @@ -395,22 +407,16 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo }); for (let j = splice[0]; j < splice[0] + splice[1]; j++) { - this._cellDisposableMapping.get(this.cells[j].handle)?.dispose(); - this._cellDisposableMapping.delete(this.cells[j].handle); + this._cellDisposableMapping.get(this._cells[j].handle)?.dispose(); + this._cellDisposableMapping.delete(this._cells[j].handle); } - const deletedItems = this.cells.splice(splice[0], splice[1], ...newCells); - - contentChangeEvents.push({ - start: splice[0], - deletedCount: splice[1], - deletedItems, - items: newCells - }); - + const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells); for (let cell of deletedItems) { removedCellDocuments.push(cell.uri); } + + contentChangeEvents.push(new RawContentChangeEvent(splice[0], splice[1], deletedItems, newCells)); }); this._documentsAndEditors.acceptDocumentsAndEditorsDelta({ @@ -421,24 +427,24 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo if (!initialization) { this._emitter.emitModelChange({ document: this, - changes: contentChangeEvents + changes: contentChangeEvents.map(RawContentChangeEvent.asApiEvent) }); } } private _moveCell(index: number, newIdx: number): void { - const cells = this.cells.splice(index, 1); - this.cells.splice(newIdx, 0, ...cells); + const cells = this._cells.splice(index, 1); + this._cells.splice(newIdx, 0, ...cells); const changes: vscode.NotebookCellsChangeData[] = [{ start: index, deletedCount: 1, - deletedItems: cells, + deletedItems: cells.map(data => data.cell), items: [] }, { start: newIdx, deletedCount: 0, deletedItems: [], - items: cells + items: cells.map(data => data.cell) }]; this._emitter.emitModelChange({ document: this, @@ -466,15 +472,15 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo } private _changeCellLanguage(index: number, language: string): void { - const cell = this.cells[index]; - const event: vscode.NotebookCellLanguageChangeEvent = { document: this, cell, language }; + const cell = this._cells[index]; + const event: vscode.NotebookCellLanguageChangeEvent = { document: this, cell: cell.cell, language }; this._emitter.emitCellLanguageChange(event); } private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata): void { - const cell = this.cells[index]; + const cell = this._cells[index]; cell.setMetadata(newMetadata); - const event: vscode.NotebookCellMetadataChangeEvent = { document: this, cell }; + const event: vscode.NotebookCellMetadataChangeEvent = { document: this, cell: cell.cell }; this._emitter.emitCellMetadataChange(event); } @@ -488,16 +494,16 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo await this._proxy.$spliceNotebookCellOutputs(this.viewType, this.uri, cell.handle, outputDtos, Array.from(renderers)); this._emitter.emitCellOutputsChange({ document: this, - cells: [cell] + cells: [cell.cell] }); } getCell(cellHandle: number): ExtHostCell | undefined { - return this.cells.find(cell => cell.handle === cellHandle); + return this._cells.find(cell => cell.handle === cellHandle); } getCell2(cellUri: UriComponents): ExtHostCell | undefined { - return this.cells.find(cell => cell.uri.fragment === cellUri.fragment); + return this._cells.find(cell => cell.uri.fragment === cellUri.fragment); } } @@ -606,7 +612,7 @@ class ExtHostWebviewCommWrapper extends Disposable { export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor { private _viewColumn: vscode.ViewColumn | undefined; - selection?: ExtHostCell = undefined; + selection?: vscode.NotebookCell; private _active: boolean = false; get active(): boolean { @@ -855,7 +861,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable { } if (cell) { - return withToken(token => (kernel.executeCell as any)(document, cell, token)); + return withToken(token => (kernel.executeCell as any)(document, cell.cell, token)); } else { return withToken(token => (kernel.executeAllCells as any)(document, token)); } @@ -869,7 +875,7 @@ export class ExtHostNotebookKernelProviderAdapter extends Disposable { } if (cell) { - return kernel.cancelCellExecution(document, cell); + return kernel.cancelCellExecution(document, cell.cell); } else { return kernel.cancelAllCellsExecution(document); } @@ -1009,7 +1015,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN outputId: output.outputId, mimeType: output.mimeType, handlerId: id, - transformedOutput: renderer.render(document, cell.outputs[output.index] as vscode.CellDisplayOutput, output.outputId, output.mimeType) + transformedOutput: renderer.render(document, cell.cell.outputs[output.index] as vscode.CellDisplayOutput, output.outputId, output.mimeType) }; }); @@ -1298,7 +1304,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN if (provider.kernel) { if (cell) { - return provider.kernel.cancelCellExecution(document, cell); + return provider.kernel.cancelCellExecution(document, cell.cell); } else { return provider.kernel.cancelAllCellsExecution(document); } @@ -1338,7 +1344,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN const cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined; if (cell) { - return withToken(token => (kernelInfo!.kernel.executeCell as any)(document, cell, token)); + return withToken(token => (kernelInfo!.kernel.executeCell as any)(document, cell.cell, token)); } else { return withToken(token => (kernelInfo!.kernel.executeAllCells as any)(document, token)); } @@ -1466,11 +1472,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN } if (data.selections) { - const cells = editor.editor.document.cells; - if (data.selections.selections.length) { const firstCell = data.selections.selections[0]; - editor.editor.selection = cells.find(cell => cell.handle === firstCell); + editor.editor.selection = editor.editor.document.getCell(firstCell)?.cell; } else { editor.editor.selection = undefined; } @@ -1502,11 +1506,9 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN document ); - const cells = editor.document.cells; - if (selections.length) { const firstCell = selections[0]; - editor.selection = cells.find(cell => cell.handle === firstCell); + editor.selection = editor.document.getCell(firstCell)?.cell; } else { editor.selection = undefined; } diff --git a/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts index 8ffeda97be3..4702e1c8165 100644 --- a/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookConcatDocument.ts @@ -6,7 +6,7 @@ import * as types from 'vs/workbench/api/common/extHostTypes'; import * as vscode from 'vscode'; import { Event, Emitter } from 'vs/base/common/event'; -import { ExtHostNotebookController, ExtHostCell } from 'vs/workbench/api/common/extHostNotebook'; +import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook'; import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer'; import { DisposableStore } from 'vs/base/common/lifecycle'; @@ -21,7 +21,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD private _disposables = new DisposableStore(); private _isClosed = false; - private _cells!: ExtHostCell[]; + private _cells!: vscode.NotebookCell[]; private _cellUris!: ResourceMap; private _cellLengths!: PrefixSumComputer; private _cellLines!: PrefixSumComputer; @@ -78,7 +78,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD for (const cell of this._notebook.cells) { if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) { this._cellUris.set(cell.uri, this._cells.length); - this._cells.push(cell); + this._cells.push(cell); cellLengths.push(cell.document.getText().length + 1); cellLineCounts.push(cell.document.lineCount); }