From de956ce8bdfad4d7093cbc17a3798cd32c48c9ae Mon Sep 17 00:00:00 2001 From: rebornix Date: Sun, 21 Feb 2021 19:35:26 -0800 Subject: [PATCH] differenciate selection and focus. --- .../api/browser/mainThreadNotebook.ts | 5 +- .../workbench/api/common/extHost.protocol.ts | 1 + .../workbench/api/common/extHostNotebook.ts | 7 +- .../contrib/bulkEdit/browser/bulkCellEdits.ts | 2 +- .../notebook/browser/contrib/coreActions.ts | 16 ++-- .../contrib/outline/notebookOutline.ts | 6 +- .../notebook/browser/diff/diffComponents.ts | 6 +- .../notebook/browser/notebookBrowser.ts | 1 + .../notebook/browser/notebookEditorWidget.ts | 7 +- .../notebook/browser/notebookServiceImpl.ts | 12 ++- .../browser/view/renderers/cellDnd.ts | 4 +- .../browser/view/renderers/cellRenderer.ts | 4 +- .../notebook/browser/viewModel/cellEdit.ts | 6 +- .../browser/viewModel/notebookViewModel.ts | 44 +++++------ .../contrib/notebook/common/model/cellEdit.ts | 19 +++-- .../common/model/notebookTextModel.ts | 79 ++++++++++--------- .../contrib/notebook/common/notebookCommon.ts | 9 ++- .../notebook/common/notebookEditorModel.ts | 2 +- .../notebook/test/notebookTextModel.test.ts | 36 ++++----- .../notebook/test/notebookViewModel.test.ts | 2 +- .../notebook/test/testNotebookEditor.ts | 4 + 21 files changed, 150 insertions(+), 122 deletions(-) diff --git a/src/vs/workbench/api/browser/mainThreadNotebook.ts b/src/vs/workbench/api/browser/mainThreadNotebook.ts index 198ed71a07e..75f61b5e428 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebook.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebook.ts @@ -163,7 +163,7 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo if (!textModel) { return false; } - return textModel.applyEdits(modelVersionId, cellEdits, true, undefined, () => undefined, undefined); + return textModel.applyEdits(modelVersionId, cellEdits, true, null, () => null, undefined); } private _isDeltaEmpty(delta: INotebookDocumentsAndEditorsDelta) { @@ -248,7 +248,8 @@ export class MainThreadNotebooks extends Disposable implements MainThreadNoteboo disposableStore.add(editor.onDidChangeSelection(() => { const selectionHandles = editor.getSelectionHandles(); - this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: selectionHandles } }); + const primarySelection = editor.getPrimarySelection(); + this._proxy.$acceptEditorPropertiesChanged(editor.getId(), { visibleRanges: null, selections: { selections: selectionHandles, primary: primarySelection } }); })); this._editorEventListenersMapping.set(editor.getId(), disposableStore); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index a4240de16af..827dcf926c1 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1742,6 +1742,7 @@ export interface ExtHostCommentsShape { } export interface INotebookSelectionChangeEvent { + primary: number | null; // handles selections: number[]; } diff --git a/src/vs/workbench/api/common/extHostNotebook.ts b/src/vs/workbench/api/common/extHostNotebook.ts index e8666b24ab9..d528fc04f57 100644 --- a/src/vs/workbench/api/common/extHostNotebook.ts +++ b/src/vs/workbench/api/common/extHostNotebook.ts @@ -589,12 +589,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape { } if (data.selections) { - if (data.selections.selections.length) { - const firstCell = data.selections.selections[0]; - editor.editor.selection = editor.editor.notebookData.getCell(firstCell)?.cell; - } else { - editor.editor.selection = undefined; - } + editor.editor.selection = data.selections.primary !== null ? editor.editor.notebookData.getCell(data.selections.primary)?.cell : undefined; editor.editor._acceptSelections(data.selections.selections); diff --git a/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts b/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts index 714e459272b..fb8674665df 100644 --- a/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts +++ b/src/vs/workbench/contrib/bulkEdit/browser/bulkCellEdits.ts @@ -56,7 +56,7 @@ export class BulkCellEdits { // apply edits const edits = group.map(entry => entry.cellEdit); - ref.object.notebook.applyEdits(ref.object.notebook.versionId, edits, true, undefined, () => undefined, this._undoRedoGroup); + ref.object.notebook.applyEdits(ref.object.notebook.versionId, edits, true, null, () => null, this._undoRedoGroup); ref.dispose(); this._progress.report(undefined); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts index 61e55c38886..64c820e1af1 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/coreActions.ts @@ -790,7 +790,7 @@ export async function changeCellToKind(kind: CellKind, context: INotebookCellAct metadata: cell.metadata, }] } - ], true, undefined, () => undefined, undefined, true); + ], true, null, () => null, undefined, true); const newCell = notebookEditor.viewModel.viewCells[idx]; if (!newCell) { @@ -1593,7 +1593,7 @@ registerAction2(class extends NotebookCellAction { return; } - editor.viewModel.notebookDocument.applyEdits(editor.viewModel.notebookDocument.versionId, [{ editType: CellEditType.Output, index, outputs: [] }], true, undefined, () => undefined, undefined); + editor.viewModel.notebookDocument.applyEdits(editor.viewModel.notebookDocument.versionId, [{ editType: CellEditType.Output, index, outputs: [] }], true, null, () => null, undefined); if (context.cell.metadata && context.cell.metadata?.runState !== NotebookCellRunState.Running) { context.notebookEditor.viewModel.notebookDocument.applyEdits(context.notebookEditor.viewModel.notebookDocument.versionId, [{ @@ -1605,7 +1605,7 @@ registerAction2(class extends NotebookCellAction { statusMessage: undefined, executionOrder: undefined } - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); } } }); @@ -1758,7 +1758,7 @@ export class ChangeCellLanguageAction extends NotebookCellAction { context.notebookEditor.viewModel.notebookDocument.applyEdits( context.notebookEditor.viewModel.notebookDocument.versionId, [{ editType: CellEditType.CellLanguage, index, language: languageId }], - true, undefined, () => undefined, undefined + true, null, () => null, undefined ); } } @@ -1808,7 +1808,7 @@ registerAction2(class extends NotebookAction { editor.viewModel.notebookDocument.applyEdits(editor.viewModel.notebookDocument.versionId, editor.viewModel.notebookDocument.cells.map((cell, index) => ({ editType: CellEditType.Output, index, outputs: [] - })), true, undefined, () => undefined, undefined); + })), true, null, () => null, undefined); const clearExecutionMetadataEdits = editor.viewModel.notebookDocument.cells.map((cell, index) => { if (cell.metadata && cell.metadata?.runState !== NotebookCellRunState.Running) { @@ -1827,7 +1827,7 @@ registerAction2(class extends NotebookAction { } }).filter(edit => !!edit) as ICellEditOperation[]; if (clearExecutionMetadataEdits.length) { - context.notebookEditor.viewModel.notebookDocument.applyEdits(context.notebookEditor.viewModel.notebookDocument.versionId, clearExecutionMetadataEdits, true, undefined, () => undefined, undefined); + context.notebookEditor.viewModel.notebookDocument.applyEdits(context.notebookEditor.viewModel.notebookDocument.versionId, clearExecutionMetadataEdits, true, null, () => null, undefined); } } }); @@ -1962,7 +1962,7 @@ abstract class ChangeNotebookCellMetadataAction extends NotebookCellAction { return; } - textModel.applyEdits(textModel.versionId, [{ editType: CellEditType.Metadata, index, metadata: { ...context.cell.metadata, ...this.getMetadataDelta() } }], true, undefined, () => undefined, undefined); + textModel.applyEdits(textModel.versionId, [{ editType: CellEditType.Metadata, index, metadata: { ...context.cell.metadata, ...this.getMetadataDelta() } }], true, null, () => null, undefined); } abstract getMetadataDelta(): NotebookCellMetadata; @@ -2116,7 +2116,7 @@ CommandsRegistry.registerCommand('notebook.trust', (accessor, args) => { const document = notebookService.listNotebookDocuments().find(document => document.uri.toString() === uri.toString()); if (document) { - document.applyEdits(document.versionId, [{ editType: CellEditType.DocumentMetadata, metadata: { ...document.metadata, ...{ trusted: true } } }], true, undefined, () => undefined, undefined, false); + document.applyEdits(document.versionId, [{ editType: CellEditType.DocumentMetadata, metadata: { ...document.metadata, ...{ trusted: true } } }], true, null, () => null, undefined, false); } }); diff --git a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts index f6c2dd20120..b0a148c5190 100644 --- a/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts +++ b/src/vs/workbench/contrib/notebook/browser/contrib/outline/notebookOutline.ts @@ -389,7 +389,7 @@ class NotebookCellOutline implements IOutline { includeCodeCells = this._configurationService.getValue('notebook.breadcrumbs.showCodeCells'); } - const [selected] = viewModel.selectionHandles; + const selected = viewModel.primarySelectionHandle; const entries: OutlineEntry[] = []; for (let i = 0; i < viewModel.viewCells.length; i++) { @@ -510,8 +510,8 @@ class NotebookCellOutline implements IOutline { let newActive: OutlineEntry | undefined; const { viewModel } = this._editor; - if (viewModel) { - const [selected] = viewModel.selectionHandles; + if (viewModel && viewModel.primarySelectionHandle !== null) { + const selected = viewModel.primarySelectionHandle; const cell = viewModel.getCellByHandle(selected); if (cell) { for (let entry of this._entries) { diff --git a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts index 235dd429996..5d4c6f34394 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/diffComponents.ts @@ -443,8 +443,8 @@ abstract class AbstractElementRenderer extends Disposable { this.notebookEditor.textModel!.versionId, [{ editType: CellEditType.CellLanguage, index, language: newLangauge }], true, - undefined, - () => undefined, + null, + () => null, undefined ); } @@ -457,7 +457,7 @@ abstract class AbstractElementRenderer extends Disposable { this.notebookEditor.textModel!.applyEdits(this.notebookEditor.textModel!.versionId, [ { editType: CellEditType.Metadata, index, metadata: result } - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); } catch { } } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index 0d3b22ff323..9976e6f297b 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -637,6 +637,7 @@ export interface INotebookCellList { focusElement(element: ICellViewModel): void; selectElement(element: ICellViewModel): void; getFocusedElements(): ICellViewModel[]; + getSelectedElements(): ICellViewModel[]; revealElementsInView(range: ICellRange): void; revealElementInView(element: ICellViewModel): void; revealElementInViewAtTop(element: ICellViewModel): void; diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts index 6d545526e57..7be50c43fac 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditorWidget.ts @@ -338,6 +338,10 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor return this.viewModel?.selectionHandles || []; } + getPrimarySelection() { + return this.viewModel?.primarySelectionHandle ?? null; + } + getSelectionViewModels(): ICellViewModel[] { if (!this.viewModel) { return []; @@ -1516,7 +1520,8 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor (direction === 'above' ? index : nextIndex) : index; const focused = this._list.getFocusedElements(); - return this.viewModel.createCell(insertIndex, initialText, language, type, undefined, [], true, undefined, focused); + const selections = this._list.getSelectedElements(); + return this.viewModel.createCell(insertIndex, initialText, language, type, undefined, [], true, undefined, focused[0]?.handle ?? null, selections); } async splitNotebookCell(cell: ICellViewModel): Promise { diff --git a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts index 036e60c5ac7..8c0f5674d57 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookServiceImpl.ts @@ -594,12 +594,18 @@ export class NotebookService extends Disposable implements INotebookService, ICu const selectionIndexes = selectedCells.map(cell => [cell, viewModel.getCellIndex(cell)] as [ICellViewModel, number]).sort((a, b) => b[1] - a[1]); const edits: ICellEditOperation[] = selectionIndexes.map(value => ({ editType: CellEditType.Replace, index: value[1], count: 1, cells: [] })); - viewModel.notebookDocument.applyEdits(viewModel.notebookDocument.versionId, edits, true, editor.getSelectionHandles(), () => { + viewModel.notebookDocument.applyEdits(viewModel.notebookDocument.versionId, edits, true, { primary: editor.getPrimarySelection(), selections: editor.getSelectionHandles() }, () => { const firstSelectIndex = selectionIndexes[0][1]; if (firstSelectIndex < viewModel.notebookDocument.cells.length) { - return [viewModel.notebookDocument.cells[firstSelectIndex].handle]; + return { + primary: viewModel.notebookDocument.cells[firstSelectIndex].handle, + selections: [viewModel.notebookDocument.cells[firstSelectIndex].handle] + }; } else { - return [viewModel.notebookDocument.cells[viewModel.notebookDocument.cells.length - 1].handle]; + return { + primary: viewModel.notebookDocument.cells[viewModel.notebookDocument.cells.length - 1].handle, + selections: [viewModel.notebookDocument.cells[viewModel.notebookDocument.cells.length - 1].handle] + }; } }, undefined, true); notebookService.setToCopy(selectedCells.map(cell => cell.model), false); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellDnd.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellDnd.ts index bb470e38229..3357441c935 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellDnd.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellDnd.ts @@ -256,7 +256,7 @@ export class CellDragAndDropController extends Disposable { } private copyCells(draggedCells: ICellViewModel[], ontoCell: ICellViewModel, direction: 'above' | 'below') { - this.notebookEditor.textModel!.pushStackElement('Copy Cells', undefined, undefined); + this.notebookEditor.textModel!.pushStackElement('Copy Cells', null, undefined); let firstNewCell: ICellViewModel | undefined = undefined; let firstNewCellState: CellEditState = CellEditState.Preview; for (let i = 0; i < draggedCells.length; i++) { @@ -273,7 +273,7 @@ export class CellDragAndDropController extends Disposable { this.notebookEditor.focusNotebookCell(firstNewCell, firstNewCellState === CellEditState.Editing ? 'editor' : 'container'); } - this.notebookEditor.textModel!.pushStackElement('Copy Cells', undefined, undefined); + this.notebookEditor.textModel!.pushStackElement('Copy Cells', null, undefined); } public startExplicitDrag(cell: ICellViewModel, position: { clientY: number }) { diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 9a1d0f3915d..3e534fb6626 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -343,11 +343,11 @@ abstract class AbstractCellRenderer { if (templateData.currentRenderedCell.metadata?.inputCollapsed) { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Metadata, index, metadata: { ...templateData.currentRenderedCell.metadata, inputCollapsed: false } } - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); } else if (templateData.currentRenderedCell.metadata?.outputCollapsed) { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Metadata, index, metadata: { ...templateData.currentRenderedCell.metadata, outputCollapsed: false } } - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); } })); } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/cellEdit.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/cellEdit.ts index 07c9350af1c..f49a28708fb 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/cellEdit.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/cellEdit.ts @@ -52,10 +52,10 @@ export class JoinCellEdit implements IResourceUndoRedoElement { const cell = this.editingDelegate.createCellViewModel(this._deletedRawCell); if (this.direction === 'above') { - this.editingDelegate.insertCell(this.index, this._deletedRawCell, [cell.handle]); + this.editingDelegate.insertCell(this.index, this._deletedRawCell, { primary: cell.handle, selections: [cell.handle] }); cell.focusMode = CellFocusMode.Editor; } else { - this.editingDelegate.insertCell(this.index, cell.model, [this.cell.handle]); + this.editingDelegate.insertCell(this.index, cell.model, { primary: this.cell.handle, selections: [this.cell.handle] }); this.cell.focusMode = CellFocusMode.Editor; } } @@ -70,7 +70,7 @@ export class JoinCellEdit implements IResourceUndoRedoElement { { range: this.inverseRange, text: this.insertContent } ]); - this.editingDelegate.deleteCell(this.index, [this.cell.handle]); + this.editingDelegate.deleteCell(this.index, { primary: this.cell.handle, selections: [this.cell.handle] }); this.cell.focusMode = CellFocusMode.Editor; } } diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts index 384b6356a0f..0cc2e5f6f24 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel.ts @@ -313,6 +313,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD } } + // TODO@rebornix this.selectionHandles = endSelectionHandles; }; @@ -341,8 +342,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD } }); - if (contentChanges.endSelections) { - this.updateSelectionsFromEdits(contentChanges.endSelections); + if (contentChanges.endSelectionState) { + this.updateSelectionsFromEdits(contentChanges.endSelectionState.primary, contentChanges.endSelectionState.selections); } })); @@ -375,8 +376,10 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD this._focused = focused; } - updateSelectionsFromEdits(selections: number[]) { + updateSelectionsFromEdits(primary: number | null, selections: number[]) { if (this._focused) { + // TODO@rebornix + this.primarySelectionHandle = primary; this.selectionHandles = selections; } } @@ -663,7 +666,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD return result; } - createCell(index: number, source: string, language: string, type: CellKind, metadata: NotebookCellMetadata | undefined, outputs: IOutputDto[], synchronous: boolean, pushUndoStop: boolean = true, previouslyFocused: ICellViewModel[] = []): CellViewModel { + createCell(index: number, source: string, language: string, type: CellKind, metadata: NotebookCellMetadata | undefined, outputs: IOutputDto[], synchronous: boolean, pushUndoStop: boolean = true, previouslyPrimary: number | null = null, previouslyFocused: ICellViewModel[] = []): CellViewModel { const beforeSelections = previouslyFocused.map(e => e.handle); this._notebook.applyEdits(this._notebook.versionId, [ { @@ -680,29 +683,25 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD } ] } - ], synchronous, beforeSelections, () => undefined, undefined); + ], synchronous, { primary: previouslyPrimary, selections: beforeSelections }, () => null, undefined); return this._viewCells[index]; } deleteCell(index: number, synchronous: boolean, pushUndoStop: boolean = true) { - const primarySelectionIndex = this.selectionHandles.length ? this._viewCells.indexOf(this.getCellByHandle(this.selectionHandles[0])!) : null; - let endSelections: number[] = []; - if (this.selectionHandles.length) { - const primarySelectionHandle = this.selectionHandles[0]; + const primaryCell = this.primarySelectionHandle !== null ? this.getCellByHandle(this.primarySelectionHandle) : null; + const primarySelectionIndex = primaryCell ? this.getCellIndex(primaryCell) : null; + let endPrimarySelection: number | null = null; - if (index === primarySelectionIndex) { - if (primarySelectionIndex < this.length - 1) { - endSelections = [this._viewCells[primarySelectionIndex + 1].handle]; - } else if (primarySelectionIndex === this.length - 1 && this.length > 1) { - endSelections = [this._viewCells[primarySelectionIndex - 1].handle]; - } else { - endSelections = []; - } - } else { - endSelections = [primarySelectionHandle]; + if (index === primarySelectionIndex) { + if (primarySelectionIndex < this.length - 1) { + endPrimarySelection = this._viewCells[primarySelectionIndex + 1].handle; + } else if (primarySelectionIndex === this.length - 1 && this.length > 1) { + endPrimarySelection = this._viewCells[primarySelectionIndex - 1].handle; } } + let endSelections: number[] = this.selectionHandles.filter(handle => handle !== endPrimarySelection); + this._notebook.applyEdits(this._notebook.versionId, [ { editType: CellEditType.Replace, @@ -711,8 +710,8 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD cells: [] }], synchronous, - this.selectionHandles, - () => endSelections, + { primary: this.primarySelectionHandle, selections: this.selectionHandles }, + () => ({ primary: endPrimarySelection, selections: endSelections }), undefined, pushUndoStop ); @@ -739,7 +738,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD length, newIdx } - ], synchronous, undefined, () => [viewCell.handle], undefined); + ], synchronous, { primary: this._primarySelectionHandle, selections: this._selections }, () => ({ primary: viewCell.handle, selections: [viewCell.handle] }), undefined); return true; } @@ -911,6 +910,7 @@ export class NotebookViewModel extends Disposable implements EditorFoldingStateD { quotableLabel: 'Join Notebook Cells' } ); + // TODO@rebornix this.selectionHandles = endSelections; return { cell: above, deletedCells: [cell] }; diff --git a/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts b/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts index 61453ae9a74..017dc4ef094 100644 --- a/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts +++ b/src/vs/workbench/contrib/notebook/common/model/cellEdit.ts @@ -8,13 +8,18 @@ import { URI } from 'vs/base/common/uri'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; import { NotebookCellMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +interface ISelectionState { + primary: number | null; + selections: number[]; +} + /** * It should not modify Undo/Redo stack */ export interface ITextCellEditingDelegate { - insertCell?(index: number, cell: NotebookCellTextModel, endSelections?: number[]): void; - deleteCell?(index: number, endSelections?: number[]): void; - moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined): void; + insertCell?(index: number, cell: NotebookCellTextModel, endSelections: ISelectionState | null): void; + deleteCell?(index: number, endSelections: ISelectionState | null): void; + moveCell?(fromIndex: number, length: number, toIndex: number, beforeSelections: ISelectionState | null, endSelections: ISelectionState | null): void; updateCellMetadata?(index: number, newMetadata: NotebookCellMetadata): void; } @@ -28,8 +33,8 @@ export class MoveCellEdit implements IResourceUndoRedoElement { private length: number, private toIndex: number, private editingDelegate: ITextCellEditingDelegate, - private beforedSelections: number[] | undefined, - private endSelections: number[] | undefined + private beforedSelections: ISelectionState | null, + private endSelections: ISelectionState | null ) { } @@ -57,8 +62,8 @@ export class SpliceCellsEdit implements IResourceUndoRedoElement { public resource: URI, private diffs: [number, NotebookCellTextModel[], NotebookCellTextModel[]][], private editingDelegate: ITextCellEditingDelegate, - private beforeHandles: number[] | undefined, - private endHandles: number[] | undefined + private beforeHandles: ISelectionState | null, + private endHandles: ISelectionState | null ) { } diff --git a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts index eb7907739e4..9ed18a6ab58 100644 --- a/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts +++ b/src/vs/workbench/contrib/notebook/common/model/notebookTextModel.ts @@ -7,7 +7,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel'; -import { INotebookTextModel, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, TransientOptions, NotebookTextModelChangedEvent, NotebookRawContentEvent, IOutputDto, ICellOutput, IOutputItemDto } from 'vs/workbench/contrib/notebook/common/notebookCommon'; +import { INotebookTextModel, NotebookCellOutputsSplice, NotebookDocumentMetadata, NotebookCellMetadata, ICellEditOperation, CellEditType, CellUri, notebookDocumentMetadataDefaults, diff, NotebookCellsChangeType, ICellDto2, TransientOptions, NotebookTextModelChangedEvent, NotebookRawContentEvent, IOutputDto, ICellOutput, IOutputItemDto, ISelectionState } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ITextSnapshot } from 'vs/editor/common/model'; import { IUndoRedoService, UndoRedoElementType, IUndoRedoElement, IResourceUndoRedoElement, UndoRedoGroup, IWorkspaceUndoRedoElement } from 'vs/platform/undoRedo/common/undoRedo'; import { MoveCellEdit, SpliceCellsEdit, CellMetadataEdit } from 'vs/workbench/contrib/notebook/common/model/cellEdit'; @@ -59,10 +59,10 @@ class StackOperation implements IWorkspaceUndoRedoElement { type: UndoRedoElementType.Workspace; private _operations: IUndoRedoElement[] = []; - private _beginSelectionState: number[] | undefined = undefined; - private _resultSelectionState: number[] | undefined = undefined; + private _beginSelectionState: ISelectionState | null = null; + private _resultSelectionState: ISelectionState | null = null; - constructor(readonly resource: URI, readonly label: string, readonly undoRedoGroup: UndoRedoGroup | undefined, private _delayedEmitter: DelayedEmitter, selectionState: number[] | undefined) { + constructor(readonly resource: URI, readonly label: string, readonly undoRedoGroup: UndoRedoGroup | undefined, private _delayedEmitter: DelayedEmitter, selectionState: ISelectionState | null) { this.type = UndoRedoElementType.Workspace; this._beginSelectionState = selectionState; } @@ -74,13 +74,13 @@ class StackOperation implements IWorkspaceUndoRedoElement { return this._operations.length === 0; } - pushEndSelectionState(selectionState: number[] | undefined) { + pushEndSelectionState(selectionState: ISelectionState | null) { this._resultSelectionState = selectionState; } - pushEditOperation(element: IUndoRedoElement, beginSelectionState: number[] | undefined, resultSelectionState: number[] | undefined) { + pushEditOperation(element: IUndoRedoElement, beginSelectionState: ISelectionState | null, resultSelectionState: ISelectionState | null) { if (this._operations.length === 0) { - this._beginSelectionState = this._beginSelectionState || beginSelectionState; + this._beginSelectionState = this._beginSelectionState ?? beginSelectionState; } this._operations.push(element); this._resultSelectionState = resultSelectionState; @@ -109,7 +109,7 @@ export class NotebookOperationManager { } - pushStackElement(label: string, selectionState: number[] | undefined, undoRedoGroup: UndoRedoGroup | undefined) { + pushStackElement(label: string, selectionState: ISelectionState | null, undoRedoGroup: UndoRedoGroup | undefined) { if (this._pendingStackOperation) { this._pendingStackOperation.pushEndSelectionState(selectionState); if (!this._pendingStackOperation.isEmpty) { @@ -122,7 +122,7 @@ export class NotebookOperationManager { this._pendingStackOperation = new StackOperation(this._resource, label, undoRedoGroup, this._delayedEmitter, selectionState); } - pushEditOperation(element: IUndoRedoElement, beginSelectionState: number[] | undefined, resultSelectionState: number[] | undefined) { + pushEditOperation(element: IUndoRedoElement, beginSelectionState: ISelectionState | null, resultSelectionState: ISelectionState | null) { if (this._pendingStackOperation) { this._pendingStackOperation.pushEditOperation(element, beginSelectionState, resultSelectionState); return; @@ -148,7 +148,7 @@ class DelayedEmitter { this._deferredCnt++; } - endDeferredEmit(endSelections: number[] | undefined): void { + endDeferredEmit(endSelections: ISelectionState | null): void { this._deferredCnt--; if (this._deferredCnt === 0) { this._computeEndState(); @@ -158,7 +158,7 @@ class DelayedEmitter { { rawEvents: this._notebookTextModelChangedEvent.rawEvents, versionId: this._textModel.versionId, - endSelections: endSelections || this._notebookTextModelChangedEvent.endSelections, + endSelectionState: endSelections, synchronous: this._notebookTextModelChangedEvent.synchronous } ); @@ -169,7 +169,7 @@ class DelayedEmitter { } - emit(data: NotebookRawContentEvent, synchronous: boolean, endSelections?: number[]) { + emit(data: NotebookRawContentEvent, synchronous: boolean, endSelections: ISelectionState | null) { if (this._deferredCnt === 0) { this._computeEndState(); @@ -178,7 +178,7 @@ class DelayedEmitter { rawEvents: [data], versionId: this._textModel.versionId, synchronous, - endSelections + endSelectionState: endSelections } ); } else { @@ -186,7 +186,7 @@ class DelayedEmitter { this._notebookTextModelChangedEvent = { rawEvents: [data], versionId: this._textModel.versionId, - endSelections: endSelections, + endSelectionState: endSelections, synchronous: synchronous }; } else { @@ -194,7 +194,10 @@ class DelayedEmitter { this._notebookTextModelChangedEvent = { rawEvents: [...this._notebookTextModelChangedEvent.rawEvents, data], versionId: this._textModel.versionId, - endSelections: endSelections ? endSelections : this._notebookTextModelChangedEvent.endSelections, + endSelectionState: { + primary: endSelections?.primary ?? null, + selections: endSelections?.selections ?? this._notebookTextModelChangedEvent.endSelectionState?.selections ?? [] + }, synchronous: synchronous }; } @@ -263,7 +266,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel for (let i = 0; i < mainCells.length; i++) { this._mapping.set(mainCells[i].handle, mainCells[i]); const dirtyStateListener = mainCells[i].onDidChangeContent(() => { - this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellContent, transient: false }, true); + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellContent, transient: false }, true, null); }); this._cellListeners.set(mainCells[i].handle, dirtyStateListener); @@ -279,11 +282,11 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel super.dispose(); } - pushStackElement(label: string, selectionState: number[] | undefined, undoRedoGroup: UndoRedoGroup | undefined) { + pushStackElement(label: string, selectionState: ISelectionState | null, undoRedoGroup: UndoRedoGroup | undefined) { this._operationManager.pushStackElement(label, selectionState, undoRedoGroup); } - applyEdits(modelVersionId: number, rawEdits: ICellEditOperation[], synchronous: boolean, beginSelectionState: number[] | undefined, endSelectionsComputer: () => number[] | undefined, undoRedoGroup: UndoRedoGroup | undefined, computeUndoRedo: boolean = true): boolean { + applyEdits(modelVersionId: number, rawEdits: ICellEditOperation[], synchronous: boolean, beginSelectionState: ISelectionState | null, endSelectionsComputer: () => ISelectionState | null, undoRedoGroup: UndoRedoGroup | undefined, computeUndoRedo: boolean = true): boolean { if (modelVersionId !== this._versionId) { return false; } @@ -351,7 +354,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel this._updateNotebookMetadata(edit.metadata, computeUndoRedo); break; case CellEditType.Move: - this._moveCellToIdx(edit.index, edit.length, edit.newIdx, synchronous, computeUndoRedo, undefined, undefined); + this._moveCellToIdx(edit.index, edit.length, edit.newIdx, synchronous, computeUndoRedo, null, null); break; } } @@ -392,7 +395,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel this._modelService ); const dirtyStateListener = cell.onDidChangeContent(() => { - this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellContent, transient: false }, true); + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellContent, transient: false }, true, null); }); this._cellListeners.set(cell.handle, dirtyStateListener); this._mapping.set(cell.handle, cell); @@ -415,9 +418,9 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel if (computeUndoRedo) { this._operationManager.pushEditOperation(new SpliceCellsEdit(this.uri, undoDiff, { - insertCell: (index, cell, endSelections?: number[]) => { this._insertNewCell(index, [cell], true, endSelections); }, - deleteCell: (index, endSelections?: number[]) => { this._removeCell(index, 1, true, endSelections); }, - }, undefined, undefined), undefined, undefined); + insertCell: (index, cell, endSelections: ISelectionState | null) => { this._insertNewCell(index, [cell], true, endSelections); }, + deleteCell: (index, endSelections: ISelectionState | null) => { this._removeCell(index, 1, true, endSelections); }, + }, null, null), null, null); } // should be deferred @@ -425,7 +428,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel kind: NotebookCellsChangeType.ModelChange, changes: diffs, transient: false - }, synchronous); + }, synchronous, null); } private _increaseVersionId(): void { @@ -467,17 +470,17 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel runState: that.metadata.runState }, false); } - }(), undefined, undefined); + }(), null, null); } - this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata, transient: this._isDocumentMetadataChangeTransient(oldMetadata, metadata) }, true); + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeDocumentMetadata, metadata: this.metadata, transient: this._isDocumentMetadataChangeTransient(oldMetadata, metadata) }, true, null); } - private _insertNewCell(index: number, cells: NotebookCellTextModel[], synchronous: boolean, endSelections?: number[]): void { + private _insertNewCell(index: number, cells: NotebookCellTextModel[], synchronous: boolean, endSelections: ISelectionState | null): void { for (let i = 0; i < cells.length; i++) { this._mapping.set(cells[i].handle, cells[i]); const dirtyStateListener = cells[i].onDidChangeContent(() => { - this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellContent, transient: false }, true); + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellContent, transient: false }, true, null); }); this._cellListeners.set(cells[i].handle, dirtyStateListener); @@ -498,7 +501,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel return; } - private _removeCell(index: number, count: number, synchronous: boolean, endSelections?: number[]) { + private _removeCell(index: number, count: number, synchronous: boolean, endSelections: ISelectionState | null) { for (let i = index; i < index + count; i++) { const cell = this._cells[i]; this._cellListeners.get(cell.handle)?.dispose(); @@ -580,7 +583,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel runState: cell.metadata.runState }, false); } - }), undefined, undefined); + }), null, null); } // should be deferred cell.metadata = metadata; @@ -588,7 +591,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel cell.metadata = metadata; } - this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellMetadata, index: this._cells.indexOf(cell), metadata: cell.metadata, transient: !triggerDirtyChange }, true); + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeCellMetadata, index: this._cells.indexOf(cell), metadata: cell.metadata, transient: !triggerDirtyChange }, true, null); } private _changeCellLanguage(handle: number, languageId: string, computeUndoRedo: boolean) { @@ -614,10 +617,10 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel redo() { that._changeCellLanguage(cell.handle, languageId, false); } - }(), undefined, undefined); + }(), null, null); } - this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeLanguage, index: this._cells.indexOf(cell), language: languageId, transient: false }, true); + this._eventEmitter.emit({ kind: NotebookCellsChangeType.ChangeLanguage, index: this._cells.indexOf(cell), language: languageId, transient: false }, true, null); } private _spliceNotebookCellOutputs2(cellHandle: number, outputs: ICellOutput[], computeUndoRedo: boolean): void { @@ -642,7 +645,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel index: this._cells.indexOf(cell), outputs: cell.outputs ?? [], transient: this.transientOptions.transientOutputs, - }, true); + }, true, null); } } @@ -667,7 +670,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel outputItems: items, append: true, transient: this.transientOptions.transientOutputs - }, true); + }, true, null); } private _replaceNotebookCellOutputItems(cellHandle: number, outputId: string, items: IOutputItemDto[]) { @@ -691,13 +694,13 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel outputItems: items, append: false, transient: this.transientOptions.transientOutputs - }, true); + }, true, null); } - private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: number[] | undefined, endSelections: number[] | undefined): boolean { + private _moveCellToIdx(index: number, length: number, newIdx: number, synchronous: boolean, pushedToUndoStack: boolean, beforeSelections: ISelectionState | null, endSelections: ISelectionState | null): boolean { if (pushedToUndoStack) { this._operationManager.pushEditOperation(new MoveCellEdit(this.uri, index, length, newIdx, { - moveCell: (fromIndex: number, length: number, toIndex: number, beforeSelections: number[] | undefined, endSelections: number[] | undefined) => { + moveCell: (fromIndex: number, length: number, toIndex: number, beforeSelections: ISelectionState | null, endSelections: ISelectionState | null) => { this._moveCellToIdx(fromIndex, length, toIndex, true, false, beforeSelections, endSelections); }, }, beforeSelections, endSelections), beforeSelections, endSelections); diff --git a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts index bd8a78be86d..0a6df61b4d2 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookCommon.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookCommon.ts @@ -298,11 +298,17 @@ export type NotebookCellsChangedEventDto = { }; export type NotebookRawContentEvent = (NotebookCellsInitializeEvent | NotebookDocumentChangeMetadataEvent | NotebookCellContentChangeEvent | NotebookCellsModelChangedEvent | NotebookCellsModelMoveEvent | NotebookOutputChangedEvent | NotebookOutputItemChangedEvent | NotebookCellsChangeLanguageEvent | NotebookCellsChangeMetadataEvent | NotebookDocumentUnknownChangeEvent) & { transient: boolean; }; + +export interface ISelectionState { + primary: number | null; + selections: number[]; +} + export type NotebookTextModelChangedEvent = { readonly rawEvents: NotebookRawContentEvent[]; readonly versionId: number; readonly synchronous: boolean; - readonly endSelections?: number[]; + readonly endSelectionState: ISelectionState | null; }; export const enum CellEditType { @@ -658,6 +664,7 @@ export interface IEditor extends editorCommon.ICompositeCodeEditor { readonly onDidChangeVisibleRanges: Event; readonly onDidChangeSelection: Event; getSelectionHandles(): number[]; + getPrimarySelection(): number | null; isNotebookEditor: boolean; visibleRanges: ICellRange[]; uri?: URI; diff --git a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts index dd58e663194..a24e9a64f0f 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookEditorModel.ts @@ -224,7 +224,7 @@ export class NotebookEditorModel extends EditorModel implements INotebookEditorM this.notebook.metadata = data.data.metadata; this.notebook.transientOptions = data.transientOptions; const edits: ICellEditOperation[] = [{ editType: CellEditType.Replace, index: 0, count: this.notebook.cells.length, cells: data.data.cells }]; - this.notebook.applyEdits(this.notebook.versionId, edits, true, undefined, () => undefined, undefined); + this.notebook.applyEdits(this.notebook.versionId, edits, true, null, () => null, undefined); } if (backupId) { diff --git a/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts index 867e0bcb193..c2a7b90ce49 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookTextModel.test.ts @@ -32,7 +32,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] }, { editType: CellEditType.Replace, index: 3, count: 0, cells: [new TestCell(viewModel.viewType, 6, 'var f = 6;', 'javascript', CellKind.Code, [], textModelService)] }, - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); assert.equal(textModel.cells.length, 6); @@ -57,7 +57,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] }, { editType: CellEditType.Replace, index: 1, count: 0, cells: [new TestCell(viewModel.viewType, 6, 'var f = 6;', 'javascript', CellKind.Code, [], textModelService)] }, - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); assert.equal(textModel.cells.length, 6); @@ -82,7 +82,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 1, cells: [] }, { editType: CellEditType.Replace, index: 3, count: 1, cells: [] }, - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); assert.equal(textModel.cells[0].getValue(), 'var a = 1;'); assert.equal(textModel.cells[1].getValue(), 'var c = 3;'); @@ -105,7 +105,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 1, cells: [] }, { editType: CellEditType.Replace, index: 3, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] }, - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); assert.equal(textModel.cells.length, 4); @@ -130,7 +130,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 1, cells: [] }, { editType: CellEditType.Replace, index: 1, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] }, - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); assert.equal(textModel.cells.length, 4); assert.equal(textModel.cells[0].getValue(), 'var a = 1;'); @@ -154,7 +154,7 @@ suite('NotebookTextModel', () => { (editor, viewModel, textModel) => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 1, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] }, - ], true, undefined, () => undefined, undefined); + ], true, null, () => null, undefined); assert.equal(textModel.cells.length, 4); assert.equal(textModel.cells[0].getValue(), 'var a = 1;'); @@ -180,7 +180,7 @@ suite('NotebookTextModel', () => { index: Number.MAX_VALUE, editType: CellEditType.Output, outputs: [] - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); }); // invalid index 2 @@ -189,7 +189,7 @@ suite('NotebookTextModel', () => { index: -1, editType: CellEditType.Output, outputs: [] - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); }); textModel.applyEdits(textModel.versionId, [{ @@ -199,7 +199,7 @@ suite('NotebookTextModel', () => { outputId: 'someId', outputs: [{ mime: 'text/markdown', value: '_Hello_' }] }] - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); assert.strictEqual(textModel.cells.length, 1); assert.strictEqual(textModel.cells[0].outputs.length, 1); @@ -213,7 +213,7 @@ suite('NotebookTextModel', () => { outputId: 'someId2', outputs: [{ mime: 'text/markdown', value: '_Hello2_' }] }] - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); assert.strictEqual(textModel.cells.length, 1); assert.strictEqual(textModel.cells[0].outputs.length, 2); @@ -229,7 +229,7 @@ suite('NotebookTextModel', () => { outputId: 'someId3', outputs: [{ mime: 'text/plain', value: 'Last, replaced output' }] }] - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); assert.strictEqual(textModel.cells.length, 1); assert.strictEqual(textModel.cells[0].outputs.length, 1); @@ -255,7 +255,7 @@ suite('NotebookTextModel', () => { index: Number.MAX_VALUE, editType: CellEditType.Metadata, metadata: { editable: false } - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); }); // invalid index 2 @@ -264,14 +264,14 @@ suite('NotebookTextModel', () => { index: -1, editType: CellEditType.Metadata, metadata: { editable: false } - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); }); textModel.applyEdits(textModel.versionId, [{ index: 0, editType: CellEditType.Metadata, metadata: { editable: false }, - }], true, undefined, () => undefined, undefined); + }], true, null, () => null, undefined); assert.equal(textModel.cells.length, 1); assert.equal(textModel.cells[0].metadata?.editable, false); @@ -300,7 +300,7 @@ suite('NotebookTextModel', () => { textModel.applyEdits(textModel.versionId, [ { editType: CellEditType.Replace, index: 1, count: 1, cells: [] }, { editType: CellEditType.Replace, index: 1, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], textModelService)] }, - ], true, undefined, () => [0], undefined); + ], true, null, () => ({ primary: 0, selections: [0] }), undefined); assert.equal(textModel.cells.length, 4); assert.equal(textModel.cells[0].getValue(), 'var a = 1;'); @@ -309,7 +309,7 @@ suite('NotebookTextModel', () => { assert.notEqual(changeEvent, undefined); assert.equal(changeEvent!.rawEvents.length, 2); - assert.deepEqual(changeEvent!.endSelections, [0]); + assert.deepEqual(changeEvent!.endSelectionState?.selections, [0]); assert.equal(textModel.versionId, version + 1); eventListener.dispose(); } @@ -341,11 +341,11 @@ suite('NotebookTextModel', () => { editType: CellEditType.Metadata, metadata: { editable: false }, } - ], true, undefined, () => [0], undefined); + ], true, null, () => ({ primary: 0, selections: [0] }), undefined); assert.notEqual(changeEvent, undefined); assert.equal(changeEvent!.rawEvents.length, 2); - assert.deepEqual(changeEvent!.endSelections, [0]); + assert.deepEqual(changeEvent!.endSelectionState?.selections, [0]); assert.equal(textModel.versionId, version + 1); eventListener.dispose(); } diff --git a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts index aa6025f2bc7..b8af391edaf 100644 --- a/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts +++ b/src/vs/workbench/contrib/notebook/test/notebookViewModel.test.ts @@ -43,7 +43,7 @@ suite('NotebookViewModel', () => { assert.equal(viewModel.viewCells[0].metadata?.editable, true); assert.equal(viewModel.viewCells[1].metadata?.editable, false); - const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true, []); + const cell = viewModel.createCell(1, 'var c = 3', 'javascript', CellKind.Code, {}, [], true, true, null, []); assert.equal(viewModel.viewCells.length, 3); assert.equal(viewModel.notebookDocument.cells.length, 3); assert.equal(viewModel.getCellIndex(cell), 1); diff --git a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts index 111be36f5b6..3a66c0451bf 100644 --- a/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/test/testNotebookEditor.ts @@ -115,6 +115,10 @@ export class TestNotebookEditor implements INotebookEditor { return []; } + getPrimarySelection() { + return null; + } + setOptions(options: NotebookEditorOptions | undefined): Promise { throw new Error('Method not implemented.');