diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index 2a85f3942294e7e96bf88c44fbd46a0dedd01150..0de2917cf3ff9c8bc9a1741b60e22b9b569edbdb 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -272,3 +272,51 @@ suite('notebook undo redo', () => { await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); }); }); + +suite('notebook working copy', () => { + test('notebook revert on close', async function () { + const resource = vscode.Uri.parse(join(vscode.workspace.rootPath || '', './first.vsctestnb')); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + await waitFor(500); + await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); + assert.equal(vscode.notebook.activeNotebookEditor!.selection?.source, ''); + + await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); + await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' }); + + // close active editor from command will revert the file + await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + await waitFor(500); + assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true); + assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true); + assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[0], vscode.notebook.activeNotebookEditor?.selection); + assert.equal(vscode.notebook.activeNotebookEditor?.selection?.source, 'test'); + + await vscode.commands.executeCommand('workbench.action.files.save'); + await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + }); + + test('notebook revert', async function () { + const resource = vscode.Uri.parse(join(vscode.workspace.rootPath || '', './first.vsctestnb')); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + await waitFor(500); + await vscode.commands.executeCommand('notebook.cell.insertCodeCellBelow'); + assert.equal(vscode.notebook.activeNotebookEditor!.selection?.source, ''); + + await vscode.commands.executeCommand('notebook.cell.insertCodeCellAbove'); + await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' }); + await vscode.commands.executeCommand('workbench.action.files.revert'); + + assert.equal(vscode.notebook.activeNotebookEditor !== undefined, true); + assert.equal(vscode.notebook.activeNotebookEditor?.selection !== undefined, true); + assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells[0], vscode.notebook.activeNotebookEditor?.selection); + assert.deepEqual(vscode.notebook.activeNotebookEditor?.document.cells.length, 1); + assert.equal(vscode.notebook.activeNotebookEditor?.selection?.source, 'test'); + + await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); + }); +}); diff --git a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts index 5f7766fd2e44503085861594cea7f31726e185cc..f82bf348e939574a1f724049dc3c618663978b06 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/notebookCellList.ts @@ -157,7 +157,7 @@ export class NotebookCellList extends WorkbenchList implements ID for (let i = diff.start; i < diff.start + diff.deleteCount; i++) { const cell = this.element(i); - if (this._viewModel!.hasCell(cell)) { + if (this._viewModel!.hasCell(cell.handle)) { hideOutputs.push(...cell?.model.outputs); } else { deletedOutputs.push(...cell?.model.outputs); @@ -177,7 +177,7 @@ export class NotebookCellList extends WorkbenchList implements ID for (let i = diff.start; i < diff.start + diff.deleteCount; i++) { const cell = this.element(i); - if (this._viewModel!.hasCell(cell)) { + if (this._viewModel!.hasCell(cell.handle)) { hideOutputs.push(...cell?.model.outputs); } else { deletedOutputs.push(...cell?.model.outputs); @@ -299,7 +299,7 @@ export class NotebookCellList extends WorkbenchList implements ID for (let i = diff.start; i < diff.start + diff.deleteCount; i++) { const cell = this.element(i); - if (this._viewModel!.hasCell(cell)) { + if (this._viewModel!.hasCell(cell.handle)) { hideOutputs.push(...cell?.model.outputs); } else { deletedOutputs.push(...cell?.model.outputs); @@ -316,6 +316,18 @@ export class NotebookCellList extends WorkbenchList implements ID splice2(start: number, deleteCount: number, elements: CellViewModel[] = []): void { // we need to convert start and delete count based on hidden ranges super.splice(start, deleteCount, elements); + + const selectionsLeft = []; + this._viewModel!.selectionHandles.forEach(handle => { + if (this._viewModel!.hasCell(handle)) { + selectionsLeft.push(handle); + } + }); + + if (!selectionsLeft.length && this._viewModel!.viewCells) { + // after splice, the selected cells are deleted + this._viewModel!.selectionHandles = [this._viewModel!.viewCells[0].handle]; + } } getViewIndex(cell: ICellViewModel) { diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts index 845b57e6e169325fc3fe1900f910cfac98f3b815..5b56bce093999b0c4fb831d8e38aa02c67990d1f 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts @@ -268,7 +268,12 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD }); diffs.reverse().forEach(diff => { - this._viewCells.splice(diff[0], diff[1], ...diff[2]); + const deletedCells = this._viewCells.splice(diff[0], diff[1], ...diff[2]); + + deletedCells.forEach(cell => { + this._handleToViewCellMapping.delete(cell.handle); + }); + diff[2].forEach(cell => { this._handleToViewCellMapping.set(cell.handle, cell); this._localStore.add(cell); @@ -456,8 +461,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD return index + 1; } - hasCell(cell: ICellViewModel) { - return this._handleToViewCellMapping.has(cell.handle); + hasCell(handle: number) { + return this._handleToViewCellMapping.has(handle); } getVersionId() { diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index 3660ea57838b236109eb41d6d5d182349afb66c6..bad8f0edc2274a32b59e959f2e6f631d3440dbb0 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -70,7 +70,6 @@ export class NotebookEditorModel extends EditorModel implements IWorkingCopy, IN } async revert(options?: IRevertOptions | undefined): Promise { - console.log(options); await this.load({ forceReadFromDisk: true }); this._dirty = false; this._onDidChangeDirty.fire();