diff --git a/src/vs/workbench/api/common/extHostNotebookDocument.ts b/src/vs/workbench/api/common/extHostNotebookDocument.ts index 73bff50d70633..c7136fa76d81d 100644 --- a/src/vs/workbench/api/common/extHostNotebookDocument.ts +++ b/src/vs/workbench/api/common/extHostNotebookDocument.ts @@ -348,7 +348,6 @@ export class ExtHostNotebookDocument extends Disposable { } acceptModelChanged(event: NotebookCellsChangedEventDto, isDirty: boolean): void { - console.log(event); this._versionId = event.versionId; this._isDirty = isDirty; event.rawEvents.forEach(e => { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts index f90c8172c403d..4fa9f6575c0b0 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor.ts @@ -217,6 +217,7 @@ export class NotebookTextDiffEditor extends EditorPane implements INotebookTextD const diffResult = await this.notebookEditorWorkerService.computeDiff(this._model.original.resource, this._model.modified.resource); const cellChanges = diffResult.cellsDiff.changes; + console.log(cellChanges); const cellDiffViewModels: CellDiffViewModel[] = []; const originalModel = this._model.original.notebook; diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts index 547f3678545ac..f0a0fd99461a5 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookSimpleWorker.ts @@ -9,7 +9,7 @@ import { URI } from 'vs/base/common/uri'; import { IRequestHandler } from 'vs/base/common/worker/simpleWorker'; import * as model from 'vs/editor/common/model'; import { PieceTreeTextBufferBuilder } from 'vs/editor/common/model/pieceTreeTextBuffer/pieceTreeTextBufferBuilder'; -import { CellKind, ICellDto2, IMainCellDto, INotebookDiffResult, IProcessedOutput, NotebookCellMetadata, NotebookDataDto, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { CellKind, ICellDto2, IMainCellDto, INotebookDiffResult, IProcessedOutput, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, NotebookDataDto, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { Range } from 'vs/editor/common/core/range'; import { EditorWorkerHost } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl'; @@ -43,10 +43,10 @@ class MirrorCell { constructor( readonly handle: number, private _source: string | string[], - readonly language: string, - readonly cellKind: CellKind, - readonly outputs: IProcessedOutput[], - readonly metadata?: NotebookCellMetadata + public language: string, + public cellKind: CellKind, + public outputs: IProcessedOutput[], + public metadata?: NotebookCellMetadata ) { } @@ -87,11 +87,52 @@ class MirrorCell { class MirrorNotebookDocument { constructor( readonly uri: URI, - readonly cells: MirrorCell[], - readonly languages: string[], - readonly metadata: NotebookDocumentMetadata, + public cells: MirrorCell[], + public languages: string[], + public metadata: NotebookDocumentMetadata, ) { } + + acceptModelChanged(event: NotebookCellsChangedEventDto) { + // note that the cell content change is not applied to the MirrorCell + // but it's fine as if a cell content is modified after the first diff, its position will not change any more + // TODO@rebornix, but it might lead to interesting bugs in the future. + event.rawEvents.forEach(e => { + if (e.kind === NotebookCellsChangeType.ModelChange) { + this._spliceNotebookCells(e.changes); + } else if (e.kind === NotebookCellsChangeType.Move) { + const cells = this.cells.splice(e.index, 1); + this.cells.splice(e.newIdx, 0, ...cells); + } else if (e.kind === NotebookCellsChangeType.Output) { + const cell = this.cells[e.index]; + cell.outputs = e.outputs; + } else if (e.kind === NotebookCellsChangeType.ChangeLanguage) { + const cell = this.cells[e.index]; + cell.language = e.language; + } else if (e.kind === NotebookCellsChangeType.ChangeCellMetadata) { + const cell = this.cells[e.index]; + cell.metadata = e.metadata; + } + }); + } + + _spliceNotebookCells(splices: NotebookCellsSplice2[]) { + splices.reverse().forEach(splice => { + const cellDtos = splice[2]; + const newCells = cellDtos.map(cell => { + return new MirrorCell( + (cell as unknown as IMainCellDto).handle, + cell.source, + cell.language, + cell.cellKind, + cell.outputs, + cell.metadata + ); + }); + + this.cells.splice(splice[0], splice[1], ...newCells); + }); + } } export class CellSequence implements ISequence { @@ -137,6 +178,13 @@ export class NotebookEditorSimpleWorker implements IRequestHandler, IDisposable )), data.languages, data.metadata); } + public acceptModelChanged(strURL: string, event: NotebookCellsChangedEventDto) { + const model = this._models[strURL]; + if (model) { + model.acceptModelChanged(event); + } + } + public acceptRemovedModel(strURL: string): void { if (!this._models[strURL]) { return; diff --git a/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts b/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts index 7693c93ec6964..a93f198dea9e0 100644 --- a/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl.ts @@ -7,7 +7,8 @@ import { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from import { URI } from 'vs/base/common/uri'; import { SimpleWorkerClient } from 'vs/base/common/worker/simpleWorker'; import { DefaultWorkerFactory } from 'vs/base/worker/defaultWorkerFactory'; -import { INotebookDiffResult } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; +import { IMainCellDto, INotebookDiffResult, NotebookCellsChangeType } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { NotebookEditorSimpleWorker } from 'vs/workbench/contrib/notebook/common/services/notebookSimpleWorker'; import { INotebookEditorWorkerService } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerService'; @@ -113,11 +114,50 @@ export class NotebookEditorModelManager extends Disposable { const toDispose = new DisposableStore(); - // TODO@rebornix, accept Model change + const cellToDto = (cell: NotebookCellTextModel): IMainCellDto => { + return { + handle: cell.handle, + uri: cell.uri, + source: cell.textBuffer.getLinesContent(), + eol: cell.textBuffer.getEOL(), + language: cell.language, + cellKind: cell.cellKind, + outputs: cell.outputs, + metadata: cell.metadata + }; + }; + + toDispose.add(model.onDidChangeContent((event) => { + const dto = event.rawEvents.map(e => { + const data = + e.kind === NotebookCellsChangeType.ModelChange || e.kind === NotebookCellsChangeType.Initialize + ? { + kind: e.kind, + versionId: event.versionId, + changes: e.changes.map(diff => [diff[0], diff[1], diff[2].map(cell => cellToDto(cell as NotebookCellTextModel))] as [number, number, IMainCellDto[]]) + } + : ( + e.kind === NotebookCellsChangeType.Move + ? { + kind: e.kind, + index: e.index, + length: e.length, + newIdx: e.newIdx, + versionId: event.versionId, + cells: e.cells.map(cell => cellToDto(cell as NotebookCellTextModel)) + } + : e + ); + + return data; + }); + + this._proxy.acceptModelChanged(modelUrl.toString(), { + rawEvents: dto, + versionId: event.versionId + }); + })); - // toDispose.add(model.onDidChangeContent((e) => { - // this._proxy.acceptModelChanged(modelUrl.toString(), e); - // })); toDispose.add(model.onWillDispose(() => { this._stopModelSync(modelUrl); }));