From b73b7469cd0ef5b5c979a714b087bf2da4e2b2f2 Mon Sep 17 00:00:00 2001 From: rebornix Date: Mon, 13 Jul 2020 13:25:57 -0700 Subject: [PATCH] fix #102423. --- .../src/notebook.test.ts | 19 ++++++++ .../notebook/browser/contrib/coreActions.ts | 45 ++++++++++++++++--- .../notebook/browser/notebookServiceImpl.ts | 12 +++-- .../notebook/common/notebookService.ts | 4 +- 4 files changed, 69 insertions(+), 11 deletions(-) diff --git a/extensions/vscode-notebook-tests/src/notebook.test.ts b/extensions/vscode-notebook-tests/src/notebook.test.ts index 9ec9163b8df..4d27d888880 100644 --- a/extensions/vscode-notebook-tests/src/notebook.test.ts +++ b/extensions/vscode-notebook-tests/src/notebook.test.ts @@ -893,6 +893,25 @@ suite('regression', () => { await vscode.commands.executeCommand('workbench.action.files.newUntitledFile', { viewType: "notebookCoreTest" }); assert.notEqual(vscode.notebook.activeNotebookEditor, undefined, 'untitled notebook editor is not undefined'); }); + + test('#102423 - copy/paste shares the same text buffer', async function () { + const resource = vscode.Uri.file(join(vscode.workspace.rootPath || '', './first.vsctestnb')); + await vscode.commands.executeCommand('vscode.openWith', resource, 'notebookCoreTest'); + + let activeCell = vscode.notebook.activeNotebookEditor!.selection; + assert.equal(activeCell?.document.getText(), 'test'); + + await vscode.commands.executeCommand('notebook.cell.copyDown'); + await vscode.commands.executeCommand('notebook.cell.edit'); + activeCell = vscode.notebook.activeNotebookEditor!.selection; + assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.indexOf(activeCell!), 1); + assert.equal(activeCell?.document.getText(), 'test'); + + await vscode.commands.executeCommand('default:type', { text: 'var abc = 0;' }); + + assert.equal(vscode.notebook.activeNotebookEditor!.document.cells.length, 2); + assert.notEqual(vscode.notebook.activeNotebookEditor!.document.cells[0].document.getText(), vscode.notebook.activeNotebookEditor!.document.cells[1].document.getText()) + }); }); suite('webview', () => { diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index d3cf36ca3e6..850f8f805ba 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -23,6 +23,7 @@ import { CellKind, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, NotebookCellRunState } from import { INotebookService } from 'vs/workbench/contrib/notebook/common/notebookService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; // Notebook Commands const EXECUTE_NOTEBOOK_COMMAND_ID = 'notebook.execute'; @@ -745,7 +746,7 @@ registerAction2(class extends NotebookAction { const clipboardService = accessor.get(IClipboardService); const notebookService = accessor.get(INotebookService); clipboardService.writeText(context.cell.getText()); - notebookService.setToCopy([context.cell.model]); + notebookService.setToCopy([context.cell.model], true); } }); @@ -774,7 +775,7 @@ registerAction2(class extends NotebookAction { } viewModel.deleteCell(viewModel.getCellIndex(context.cell), true); - notebookService.setToCopy([context.cell.model]); + notebookService.setToCopy([context.cell.model], false); } }); @@ -794,7 +795,7 @@ registerAction2(class extends NotebookAction { async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext) { const notebookService = accessor.get(INotebookService); - const pasteCells = notebookService.getToCopy() || []; + const pasteCells = notebookService.getToCopy(); const viewModel = context.notebookEditor.viewModel; @@ -802,9 +803,25 @@ registerAction2(class extends NotebookAction { return; } + if (!pasteCells) { + return; + } + const currCellIndex = viewModel.getCellIndex(context!.cell); - pasteCells.reverse().forEach(pasteCell => { + pasteCells.items.reverse().map(cell => { + if (pasteCells.isCopy) { + return viewModel.notebookDocument.createCellTextModel( + cell.getValue(), + cell.language, + cell.cellKind, + [], + cell.metadata + ); + } else { + return cell; + } + }).forEach(pasteCell => { viewModel.insertCell(currCellIndex, pasteCell, true); return; }); @@ -826,7 +843,7 @@ registerAction2(class extends NotebookAction { async runWithContext(accessor: ServicesAccessor, context: INotebookCellActionContext) { const notebookService = accessor.get(INotebookService); - const pasteCells = notebookService.getToCopy() || []; + const pasteCells = notebookService.getToCopy(); const viewModel = context.notebookEditor.viewModel; @@ -834,9 +851,25 @@ registerAction2(class extends NotebookAction { return; } + if (!pasteCells) { + return; + } + const currCellIndex = viewModel.getCellIndex(context!.cell); - pasteCells.reverse().forEach(pasteCell => { + pasteCells.items.reverse().map(cell => { + if (pasteCells.isCopy) { + return viewModel.notebookDocument.createCellTextModel( + cell.getValue(), + cell.language, + cell.cellKind, + [], + cell.metadata + ); + } else { + return cell; + } + }).forEach(pasteCell => { viewModel.insertCell(currCellIndex + 1, pasteCell, true); return; }); diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 4a10bb16f0a..0f22ba6b4c4 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -190,6 +190,7 @@ export class NotebookService extends Disposable implements INotebookService, ICu private readonly _onDidChangeKernels = new Emitter(); onDidChangeKernels: Event = this._onDidChangeKernels.event; private cutItems: NotebookCellTextModel[] | undefined; + private _lastClipboardIsCopy: boolean = true; private _displayOrder: { userOrder: string[], defaultOrder: string[] } = Object.create(null); @@ -728,12 +729,17 @@ export class NotebookService extends Disposable implements INotebookService, ICu this._onDidChangeVisibleEditors.fire(alreadyCreated); } - setToCopy(items: NotebookCellTextModel[]) { + setToCopy(items: NotebookCellTextModel[], isCopy: boolean) { this.cutItems = items; + this._lastClipboardIsCopy = isCopy; } - getToCopy(): NotebookCellTextModel[] | undefined { - return this.cutItems; + getToCopy(): { items: NotebookCellTextModel[], isCopy: boolean; } | undefined { + if (this.cutItems) { + return { items: this.cutItems, isCopy: this._lastClipboardIsCopy }; + } + + return undefined; } async save(viewType: string, resource: URI, token: CancellationToken): Promise { diff --git a/src/vs/workbench/contrib/notebook/common/notebookService.ts b/src/vs/workbench/contrib/notebook/common/notebookService.ts index dc8b486b467..ce9af73ad67 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookService.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookService.ts @@ -66,8 +66,8 @@ export interface INotebookService { saveAs(viewType: string, resource: URI, target: URI, token: CancellationToken): Promise; backup(viewType: string, uri: URI, token: CancellationToken): Promise; onDidReceiveMessage(viewType: string, editorId: string, rendererType: string | undefined, message: unknown): void; - setToCopy(items: NotebookCellTextModel[]): void; - getToCopy(): NotebookCellTextModel[] | undefined; + setToCopy(items: NotebookCellTextModel[], isCopy: boolean): void; + getToCopy(): { items: NotebookCellTextModel[], isCopy: boolean; } | undefined; // editor events addNotebookEditor(editor: IEditor): void;