diff --git a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts index ad28059c6a1..2c73b2b2a32 100644 --- a/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts +++ b/src/vs/workbench/contrib/chat/browser/chatEditing/chatEditingModifiedNotebookEntry.ts @@ -660,22 +660,11 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie private undoPreviouslyInsertedCell(cell: NotebookCellTextModel) { const index = this.modifiedModel.cells.indexOf(cell); - const diff = sortCellChanges(this._cellsDiffInfo.get()).slice().map(d => { - if (d.type === 'insert' && d.modifiedCellIndex === index) { - return d; - } - if (d.type !== 'delete' && d.modifiedCellIndex > index) { - return { - ...d, - modifiedCellIndex: d.modifiedCellIndex - 1, - }; - } - return d; - }).filter(d => !(d.type === 'insert' && d.modifiedCellIndex === index)); - const edit: ICellReplaceEdit = { cells: [], count: 1, editType: CellEditType.Replace, index, }; - this.modifiedModel.applyEdits([edit], true, undefined, () => undefined, undefined, true); + const diffs = adjustCellDiffForRevertingAnInsertedCell(index, + this._cellsDiffInfo.get(), + this.modifiedModel.applyEdits.bind(this.modifiedModel)); this.disposeDeletedCellEntries(); - this.updateCellDiffInfo(diff, undefined); + this.updateCellDiffInfo(diffs, undefined); } private keepPreviouslyInsertedCell(cell: NotebookCellTextModel) { @@ -684,16 +673,6 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie // Not possible. return; } - // Find where we should insert this cell in the original notebook. - const cellDiffs = sortCellChanges(this._cellsDiffInfo.get()).slice(); - const entryIndex = cellDiffs.findIndex(d => d.type === 'insert' && d.modifiedCellIndex === modifiedCellIndex); - if (entryIndex === -1) { - // Not possible. - return; - } - // Find the index in original notebook where this cell must be inserted.. - // If there are cells before this then insert just after that else start at index 0. - const index = (cellDiffs.slice(0, entryIndex).reverse().find(c => typeof c.originalCellIndex === 'number')?.originalCellIndex ?? -1) + 1; const cellToInsert: ICellDto2 = { cellKind: cell.cellKind, language: cell.language, @@ -705,35 +684,19 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie cellId: cell.internalMetadata.cellId } }; - const edit: ICellReplaceEdit = { cells: [cellToInsert], count: 0, editType: CellEditType.Replace, index, }; - this.originalModel.applyEdits([edit], true, undefined, () => undefined, undefined, true); this.cellEntryMap.get(cell.uri)?.dispose(); this.cellEntryMap.delete(cell.uri); - const unchangedCell: ICellDiffInfo = this.createModifiedCellDiffInfo(modifiedCellIndex, index); - cellDiffs.splice(entryIndex, 1, unchangedCell); + const cellDiffs = adjustCellDiffForKeepingAnInsertedCell( + modifiedCellIndex, + this._cellsDiffInfo.get().slice(), + cellToInsert, + this.originalModel.applyEdits.bind(this.originalModel), + this.createModifiedCellDiffInfo.bind(this) + ); this.updateCellDiffInfo(cellDiffs, undefined); } private undoPreviouslyDeletedCell(deletedOriginalIndex: number, originalCell: NotebookCellTextModel) { - let cellDiffs = sortCellChanges(this._cellsDiffInfo.get()).slice(); - // Find where we should insert this cell. - const cellDiffInfoIndex = cellDiffs.findIndex(d => d.type === 'delete' && d.originalCellIndex === deletedOriginalIndex); - if (cellDiffInfoIndex === -1) { - return; - } - // If there are no more cells, then start at index 0, else start at the previous cell. - const index = (cellDiffs.slice(0, cellDiffInfoIndex).reverse().find(c => c.type !== 'delete')?.modifiedCellIndex ?? -1) + 1; - cellDiffs = cellDiffs - .map(d => { - if (d.type !== 'delete' && d.modifiedCellIndex >= index) { - return { - ...d, - modifiedCellIndex: d.modifiedCellIndex + 1, - }; - } - return d; - }); - const cellToInsert: ICellDto2 = { cellKind: originalCell.cellKind, language: originalCell.language, @@ -745,10 +708,13 @@ export class ChatEditingModifiedNotebookEntry extends AbstractChatEditingModifie cellId: originalCell.internalMetadata.cellId } }; - const edit: ICellReplaceEdit = { cells: [cellToInsert], count: 0, editType: CellEditType.Replace, index, }; - this.modifiedModel.applyEdits([edit], true, undefined, () => undefined, undefined, true); - const unchangedCell = this.createModifiedCellDiffInfo(index, deletedOriginalIndex); - cellDiffs.splice(cellDiffInfoIndex, 1, unchangedCell); + const cellDiffs = adjustCellDiffForRevertingADeletedCell( + deletedOriginalIndex, + this._cellsDiffInfo.get(), + cellToInsert, + this.modifiedModel.applyEdits.bind(this.modifiedModel), + this.createModifiedCellDiffInfo.bind(this) + ); this.updateCellDiffInfo(cellDiffs, undefined); } @@ -1242,6 +1208,128 @@ class ChatEditingNotebookCellEntry extends ObservableDisposable { } } +export function adjustCellDiffForKeepingADeletedCell(originalCellIndex: number, + cellDiffInfo: ICellDiffInfo[], + applyEdits: typeof NotebookTextModel.prototype.applyEdits, +): ICellDiffInfo[] { + // Delete this cell from original as well. + const edit: ICellReplaceEdit = { cells: [], count: 1, editType: CellEditType.Replace, index: originalCellIndex, }; + applyEdits([edit], true, undefined, () => undefined, undefined, true); + const diffs = sortCellChanges(cellDiffInfo) + .filter(d => !(d.type === 'delete' && d.originalCellIndex === originalCellIndex)) + .map(diff => { + if (diff.type !== 'insert' && diff.originalCellIndex > originalCellIndex) { + return { + ...diff, + originalCellIndex: diff.originalCellIndex - 1, + }; + } + return diff; + }); + return diffs; +} + +export function adjustCellDiffForRevertingADeletedCell(originalCellIndex: number, + cellDiffInfo: ICellDiffInfo[], + cellToInsert: ICellDto2, + applyEdits: typeof NotebookTextModel.prototype.applyEdits, + createModifiedCellDiffInfo: (modifiedCellIndex: number, originalCellIndex: number) => ICellDiffInfo, +): ICellDiffInfo[] { + cellDiffInfo = sortCellChanges(cellDiffInfo); + const indexOfEntry = cellDiffInfo.findIndex(d => d.originalCellIndex === originalCellIndex); + if (indexOfEntry === -1) { + // Not possible. + return cellDiffInfo; + } + + let modifiedCellIndex = -1; + for (let i = 0; i < cellDiffInfo.length; i++) { + const diff = cellDiffInfo[i]; + if (i < indexOfEntry) { + modifiedCellIndex = Math.max(modifiedCellIndex, diff.modifiedCellIndex ?? modifiedCellIndex); + continue; + } + if (i === indexOfEntry) { + const edit: ICellReplaceEdit = { cells: [cellToInsert], count: 0, editType: CellEditType.Replace, index: modifiedCellIndex + 1, }; + applyEdits([edit], true, undefined, () => undefined, undefined, true); + cellDiffInfo[i] = createModifiedCellDiffInfo(modifiedCellIndex + 1, originalCellIndex); + continue; + } else { + // Increase the original index for all entries after this. + if (typeof diff.modifiedCellIndex === 'number') { + diff.modifiedCellIndex++; + cellDiffInfo[i] = { ...diff }; + } + } + } + + return cellDiffInfo; +} + +export function adjustCellDiffForRevertingAnInsertedCell(modifiedCellIndex: number, + cellDiffInfo: ICellDiffInfo[], + applyEdits: typeof NotebookTextModel.prototype.applyEdits, +): ICellDiffInfo[] { + if (modifiedCellIndex === -1) { + // Not possible. + return cellDiffInfo; + } + cellDiffInfo = sortCellChanges(cellDiffInfo).map(d => { + if (d.type === 'insert' && d.modifiedCellIndex === modifiedCellIndex) { + return d; + } + if (d.type !== 'delete' && d.modifiedCellIndex > modifiedCellIndex) { + return { + ...d, + modifiedCellIndex: d.modifiedCellIndex - 1, + }; + } + return d; + }).filter(d => !(d.type === 'insert' && d.modifiedCellIndex === modifiedCellIndex)); + const edit: ICellReplaceEdit = { cells: [], count: 1, editType: CellEditType.Replace, index: modifiedCellIndex, }; + applyEdits([edit], true, undefined, () => undefined, undefined, true); + return cellDiffInfo; +} + +export function adjustCellDiffForKeepingAnInsertedCell(modifiedCellIndex: number, + cellDiffInfo: ICellDiffInfo[], + cellToInsert: ICellDto2, + applyEdits: typeof NotebookTextModel.prototype.applyEdits, + createModifiedCellDiffInfo: (modifiedCellIndex: number, originalCellIndex: number) => ICellDiffInfo, +): ICellDiffInfo[] { + cellDiffInfo = sortCellChanges(cellDiffInfo); + if (modifiedCellIndex === -1) { + // Not possible. + return cellDiffInfo; + } + const indexOfEntry = cellDiffInfo.findIndex(d => d.modifiedCellIndex === modifiedCellIndex); + if (indexOfEntry === -1) { + // Not possible. + return cellDiffInfo; + } + let originalCellIndex = -1; + for (let i = 0; i < cellDiffInfo.length; i++) { + const diff = cellDiffInfo[i]; + if (i < indexOfEntry) { + originalCellIndex = Math.max(originalCellIndex, diff.originalCellIndex ?? originalCellIndex); + continue; + } + if (i === indexOfEntry) { + const edit: ICellReplaceEdit = { cells: [cellToInsert], count: 0, editType: CellEditType.Replace, index: originalCellIndex + 1 }; + applyEdits([edit], true, undefined, () => undefined, undefined, true); + cellDiffInfo[i] = createModifiedCellDiffInfo(modifiedCellIndex, originalCellIndex + 1); + continue; + } else { + // Increase the original index for all entries after this. + if (typeof diff.originalCellIndex === 'number') { + diff.originalCellIndex++; + cellDiffInfo[i] = { ...diff }; + } + } + } + return cellDiffInfo; +} + export function adjustCellDiffAndOriginalModelBasedOnCellAddDelete(change: NotebookCellTextModelSplice, cellDiffInfo: ICellDiffInfo[], modifiedModelCellCount: number, @@ -1249,7 +1337,7 @@ export function adjustCellDiffAndOriginalModelBasedOnCellAddDelete(change: Noteb applyEdits: typeof NotebookTextModel.prototype.applyEdits, createModifiedCellDiffInfo: (modifiedCellIndex: number, originalCellIndex: number) => ICellDiffInfo, ): ICellDiffInfo[] { - cellDiffInfo = sortCellChanges(cellDiffInfo).slice(); + cellDiffInfo = sortCellChanges(cellDiffInfo); const numberOfCellsInserted = change[2].length; const numberOfCellsDeleted = change[1]; const cells = change[2].map(cell => { @@ -1314,6 +1402,19 @@ export function adjustCellDiffAndOriginalModelBasedOnCellAddDelete(change: Noteb cellDiffInfo[i] = { ...diff }; } } + if (itemsToRemove.size) { + Array.from(itemsToRemove) + .filter(diff => typeof diff.originalCellIndex === 'number') + .forEach(diff => { + const edit: ICellEditOperation = { + editType: CellEditType.Replace, + cells: [], + index: diff.originalCellIndex, + count: 1 + }; + applyEdits([edit], true, undefined, () => undefined, undefined, true); + }); + } cellDiffInfo = cellDiffInfo.filter(d => !itemsToRemove.has(d)); } @@ -1348,6 +1449,7 @@ export function adjustCellDiffAndOriginalModelBasedOnCellAddDelete(change: Noteb }); return cellDiffInfo; } + /** * Given the movements of cells in modified notebook, adjust the ICellDiffInfo[] array * and generate edits for the old notebook (if required). diff --git a/src/vs/workbench/contrib/chat/test/browser/chatEditingModifiedNotebookEntry.test.ts b/src/vs/workbench/contrib/chat/test/browser/chatEditingModifiedNotebookEntry.test.ts index 17201568d18..b35621346ed 100644 --- a/src/vs/workbench/contrib/chat/test/browser/chatEditingModifiedNotebookEntry.test.ts +++ b/src/vs/workbench/contrib/chat/test/browser/chatEditingModifiedNotebookEntry.test.ts @@ -5,7 +5,7 @@ import assert from 'assert'; import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js'; -import { adjustCellDiffAndOriginalModelBasedOnCellAddDelete, adjustCellDiffAndOriginalModelBasedOnCellMovements } from '../../browser/chatEditing/chatEditingModifiedNotebookEntry.js'; +import { adjustCellDiffAndOriginalModelBasedOnCellAddDelete, adjustCellDiffAndOriginalModelBasedOnCellMovements, adjustCellDiffForKeepingADeletedCell, adjustCellDiffForKeepingAnInsertedCell, adjustCellDiffForRevertingADeletedCell, adjustCellDiffForRevertingAnInsertedCell } from '../../browser/chatEditing/chatEditingModifiedNotebookEntry.js'; import { ICellDiffInfo } from '../../browser/chatEditing/chatEditingNotebookEditorIntegration.js'; import { nullDocumentDiff } from '../../../../../editor/common/diff/documentDiffProvider.js'; import { ObservablePromise, observableValue } from '../../../../../base/common/observable.js'; @@ -15,1023 +15,1801 @@ import { URI } from '../../../../../base/common/uri.js'; import { hash } from '../../../../../base/common/hash.js'; import { generateUuid } from '../../../../../base/common/uuid.js'; -suite('ChatEditingModifiedNotebookEntry Cell Addition', function () { +suite('ChatEditingModifiedNotebookEntry', function () { + suite('Keep Inserted Cell', function () { - const keep = () => Promise.resolve(true); - const undo = () => Promise.resolve(true); - const diff = observableValue('cell1', nullDocumentDiff); - const appliedEdits: ICellEditOperation[] = []; - setup(() => { - appliedEdits.length = 0; + const keep = () => Promise.resolve(true); + const undo = () => Promise.resolve(true); + const diff = observableValue('cell1', nullDocumentDiff); + const appliedEdits: ICellEditOperation[] = []; + setup(() => { + appliedEdits.length = 0; + }); + ensureNoDisposablesAreLeakedInTestSuite(); + function createModifiedModel(id: string): ObservablePromise { + return `Modified:${id}` as any; + + } + function createOriginalModel(id: string): ObservablePromise { + return `Original:${id}` as any; + + } + function applyEdits(edits: ICellEditOperation[]): boolean { + appliedEdits.push(...edits); + return true; + } + + function createModifiedCellDiffInfo(modifiedCellIndex: number, originalCellIndex: number): ICellDiffInfo { + return { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:${originalCellIndex}`), originalCellIndex, + modifiedCellIndex, modifiedModel: createModifiedModel(`InsertedModified:${modifiedCellIndex}`), + }; + } + test('Keep first inserted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]; + + const result = adjustCellDiffForKeepingAnInsertedCell(0, + cellsDiffInfo, {} as any, + applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [{}], count: 0 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:0`), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel(`InsertedModified:0`), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Keep first inserted with multiple cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]; + + const result = adjustCellDiffForKeepingAnInsertedCell(0, + cellsDiffInfo, {} as any, + applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [{}], count: 0 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('InsertedOriginal:0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('InsertedModified:0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 3, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]); + }); + test('Keep second inserted with multiple cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]; + + const result = adjustCellDiffForKeepingAnInsertedCell(2, + cellsDiffInfo, {} as any, + applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 2, cells: [{}], count: 0 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('InsertedOriginal:2'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('InsertedModified:2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 3, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]); + }); }); - ensureNoDisposablesAreLeakedInTestSuite(); - function createModifiedModel(id: string): ObservablePromise { - return `Modified:${id}` as any; - } - function createOriginalModel(id: string): ObservablePromise { - return `Original:${id}` as any; + suite('Revert Inserted Cell', function () { - } - function applyEdits(edits: ICellEditOperation[]): boolean { - appliedEdits.push(...edits); - return true; - } + const keep = () => Promise.resolve(true); + const undo = () => Promise.resolve(true); + const diff = observableValue('cell1', nullDocumentDiff); + const appliedEdits: ICellEditOperation[] = []; + setup(() => { + appliedEdits.length = 0; + }); + ensureNoDisposablesAreLeakedInTestSuite(); + function createModifiedModel(id: string): ObservablePromise { + return `Modified:${id}` as any; - function createICell(cellKind: CellKind, source: string): ICell { - const handle = hash(generateUuid()); - return { - uri: URI.parse(`file:///path/${handle}`), - handle, - cellKind, - language: cellKind === CellKind.Markup ? 'markdown' : 'python', - outputs: [], - metadata: {}, - getHashValue: () => { - return hash(`${handle}=>${cellKind}=>${source}`); - }, - getValue: () => { - return source; - }, - internalMetadata: {}, - } as any; - } - function createModifiedCellDiffInfo(modifiedCellIndex: number, originalCellIndex: number): ICellDiffInfo { - return { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:${originalCellIndex}`), originalCellIndex, - modifiedCellIndex, modifiedModel: createModifiedModel(`InsertedModified:${modifiedCellIndex}`), - }; - } - test('Insert a new cell into an unchanged notebook', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - ]; + } + function createOriginalModel(id: string): ObservablePromise { + return `Original:${id}` as any; - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([0, 0, [createICell(CellKind.Code, 'print("Hello World")')]], - cellsDiffInfo, 2, 2, applyEdits, createModifiedCellDiffInfo); + } + function applyEdits(edits: ICellEditOperation[]): boolean { + appliedEdits.push(...edits); + return true; + } - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:0`), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel(`InsertedModified:0`), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 2, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), - }, - ]); + test('Delete first inserted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]; + + const result = adjustCellDiffForRevertingAnInsertedCell(0, + cellsDiffInfo, + applyEdits); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [], count: 1 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Delete first inserted with multiple cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]; + + const result = adjustCellDiffForRevertingAnInsertedCell(0, + cellsDiffInfo, + applyEdits); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [], count: 1 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + ]); + }); + test('Delete second inserted with multiple cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]; + + const result = adjustCellDiffForRevertingAnInsertedCell(2, + cellsDiffInfo, + applyEdits); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 2, cells: [], count: 1 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + ]); + }); }); - test('Insert a new cell into an notebook with 3 cells deleted', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([2, 0, [createICell(CellKind.Code, 'print("Hello World")')]], - cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); + suite('Keep Deleted Cell', function () { - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:4`), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel(`InsertedModified:2`), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 6, - modifiedCellIndex: 4, modifiedModel: createModifiedModel('1'), - }, - ]); + const keep = () => Promise.resolve(true); + const undo = () => Promise.resolve(true); + const diff = observableValue('cell1', nullDocumentDiff); + const appliedEdits: ICellEditOperation[] = []; + setup(() => { + appliedEdits.length = 0; + }); + ensureNoDisposablesAreLeakedInTestSuite(); + function createModifiedModel(id: string): ObservablePromise { + return `Modified:${id}` as any; + + } + function createOriginalModel(id: string): ObservablePromise { + return `Original:${id}` as any; + + } + function applyEdits(edits: ICellEditOperation[]): boolean { + appliedEdits.push(...edits); + return true; + } + + test('Keep first deleted cell', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]; + + const result = adjustCellDiffForKeepingADeletedCell(0, + cellsDiffInfo, + applyEdits); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [], count: 1 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Keep second deleted cell', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]; + + const result = adjustCellDiffForKeepingADeletedCell(1, + cellsDiffInfo, + applyEdits); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 1, cells: [], count: 1 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + + test('Keep first deleted with multiple cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]; + + const result = adjustCellDiffForKeepingADeletedCell(1, + cellsDiffInfo, + applyEdits); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 1, cells: [], count: 1 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]); + }); }); - test('Insert 2 new cells into an notebook with 3 cells deleted', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([2, 0, [createICell(CellKind.Code, 'print("Hello World")'), createICell(CellKind.Code, 'print("Foo Bar")')]], - cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); + suite('Revert Deleted Cell', function () { - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:4`), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel(`InsertedModified:2`), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:5`), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel(`InsertedModified:3`), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 6, - modifiedCellIndex: 4, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 7, - modifiedCellIndex: 5, modifiedModel: createModifiedModel('1'), - }, - ]); + const keep = () => Promise.resolve(true); + const undo = () => Promise.resolve(true); + const diff = observableValue('cell1', nullDocumentDiff); + const appliedEdits: ICellEditOperation[] = []; + setup(() => { + appliedEdits.length = 0; + }); + ensureNoDisposablesAreLeakedInTestSuite(); + function createModifiedModel(id: string): ObservablePromise { + return `Modified:${id}` as any; + + } + function createOriginalModel(id: string): ObservablePromise { + return `Original:${id}` as any; + + } + function applyEdits(edits: ICellEditOperation[]): boolean { + appliedEdits.push(...edits); + return true; + } + function createModifiedCellDiffInfo(modifiedCellIndex: number, originalCellIndex: number): ICellDiffInfo { + return { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:${originalCellIndex}`), originalCellIndex, + modifiedCellIndex, modifiedModel: createModifiedModel(`InsertedModified:${modifiedCellIndex}`), + }; + } + + test('Revert first deleted cell', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]; + + const result = adjustCellDiffForRevertingADeletedCell(0, + cellsDiffInfo, + {} as any, + applyEdits, + createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [{}], count: 0 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('InsertedOriginal:0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('InsertedModified:0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Revert second deleted cell', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]; + + const result = adjustCellDiffForRevertingADeletedCell(1, + cellsDiffInfo, + {} as any, + applyEdits, + createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 0, cells: [{}], count: 0 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('InsertedOriginal:1'), originalCellIndex: 1, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('InsertedModified:0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + + test('Revert first deleted with multiple cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 4, modifiedModel: createModifiedModel('2'), + }, + ]; + + const result = adjustCellDiffForRevertingADeletedCell(1, + cellsDiffInfo, + {} as any, + applyEdits, + createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { editType: CellEditType.Replace, index: 3, cells: [{}], count: 0 }, + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('New0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('InsertedOriginal:1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('InsertedModified:3'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 4, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: 5, modifiedModel: createModifiedModel('2'), + }, + ]); + }); }); - test('Delete a cell from an unchanged notebook', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([0, 1, []], - cellsDiffInfo, 2, 2, applyEdits, createModifiedCellDiffInfo); + suite('Cell Addition', function () { - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), - }, - ]); + const keep = () => Promise.resolve(true); + const undo = () => Promise.resolve(true); + const diff = observableValue('cell1', nullDocumentDiff); + const appliedEdits: ICellEditOperation[] = []; + setup(() => { + appliedEdits.length = 0; + }); + ensureNoDisposablesAreLeakedInTestSuite(); + function createModifiedModel(id: string): ObservablePromise { + return `Modified:${id}` as any; + + } + function createOriginalModel(id: string): ObservablePromise { + return `Original:${id}` as any; + + } + function applyEdits(edits: ICellEditOperation[]): boolean { + appliedEdits.push(...edits); + return true; + } + + function createICell(cellKind: CellKind, source: string): ICell { + const handle = hash(generateUuid()); + return { + uri: URI.parse(`file:///path/${handle}`), + handle, + cellKind, + language: cellKind === CellKind.Markup ? 'markdown' : 'python', + outputs: [], + metadata: {}, + getHashValue: () => { + return hash(`${handle}=>${cellKind}=>${source}`); + }, + getValue: () => { + return source; + }, + internalMetadata: {}, + } as any; + } + function createModifiedCellDiffInfo(modifiedCellIndex: number, originalCellIndex: number): ICellDiffInfo { + return { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:${originalCellIndex}`), originalCellIndex, + modifiedCellIndex, modifiedModel: createModifiedModel(`InsertedModified:${modifiedCellIndex}`), + }; + } + test('Insert a new cell into an unchanged notebook', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + ]; + + const cell = createICell(CellKind.Code, 'print("Hello World")'); + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([0, 0, [cell]], + cellsDiffInfo, 2, 2, applyEdits, createModifiedCellDiffInfo); + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 0, + cells: [{ + cellKind: CellKind.Code, + language: 'python', + outputs: [], + mime: undefined, + metadata: {}, + internalMetadata: {}, + source: cell.getValue(), + }], count: 0 + } + ]); + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:0`), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel(`InsertedModified:0`), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Insert a new cell into an notebook with 3 cells deleted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('4'), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('4'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'modified', originalModel: createOriginalModel('6'), originalCellIndex: 6, + modifiedCellIndex: 4, modifiedModel: createModifiedModel('6'), + }, + ]; + const cell = createICell(CellKind.Code, 'print("Hello World")'); + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([2, 0, [cell]], + cellsDiffInfo, 5, 7, applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 4, + cells: [{ + cellKind: CellKind.Code, + language: 'python', + outputs: [], + mime: undefined, + metadata: {}, + internalMetadata: {}, + source: cell.getValue(), + }], count: 0 + } + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('InsertedOriginal:4'), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('InsertedModified:2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('4'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('4'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 6, + modifiedCellIndex: 4, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'modified', originalModel: createOriginalModel('6'), originalCellIndex: 7, + modifiedCellIndex: 5, modifiedModel: createModifiedModel('6'), + }, + ]); + }); + test('Insert 2 new cells into an notebook with 3 cells deleted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), + }, + ]; + const cell1 = createICell(CellKind.Code, 'print("Hello World")'); + const cell2 = createICell(CellKind.Code, 'print("Foo Bar")'); + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([2, 0, [cell1, cell2]], + cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 4, + cells: [{ + cellKind: CellKind.Code, + language: 'python', + outputs: [], + mime: undefined, + metadata: {}, + internalMetadata: {}, + source: cell1.getValue(), + }, { + cellKind: CellKind.Code, + language: 'python', + outputs: [], + mime: undefined, + metadata: {}, + internalMetadata: {}, + source: cell2.getValue(), + }], count: 0 + } + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:4`), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel(`InsertedModified:2`), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel(`InsertedOriginal:5`), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel(`InsertedModified:3`), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 6, + modifiedCellIndex: 4, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 7, + modifiedCellIndex: 5, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Delete a cell from an unchanged notebook', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + ]; + + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([0, 1, []], + cellsDiffInfo, 2, 2, applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 0, + cells: [], count: 1 + } + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Delete last cell from an unchanged notebook', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + ]; + + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 1, []], + cellsDiffInfo, 2, 2, applyEdits, createModifiedCellDiffInfo); + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 1, + cells: [], count: 1 + } + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Delete a new cell from a notebook with 3 cells deleted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), + }, + ]; + + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 1, [ + // createICell(CellKind.Code, 'print("Hello World")') + ]], + cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Delete 2 cells from a notebook with 3 cells deleted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), + }, + ]; + + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 2, [ + ]], + cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 4, + cells: [], count: 1 + } + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 4, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Delete 3 cells from a notebook with 3 cells deleted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'modified', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('6'), originalCellIndex: 6, + modifiedCellIndex: 4, modifiedModel: createModifiedModel('6'), + }, + ]; + + const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 3, [ + ]], + cellsDiffInfo, 5, 7, applyEdits, createModifiedCellDiffInfo); + + assert.deepStrictEqual(appliedEdits, [ + { + editType: CellEditType.Replace, + index: 1, + cells: [], count: 1 + }, + { + editType: CellEditType.Replace, + index: 5, + cells: [], count: 1 + } + ]); + + assert.deepStrictEqual(result, [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('6'), originalCellIndex: 4, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('6'), + }, + ]); + }); }); - test('Delete last cell from an unchanged notebook', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 1, []], - cellsDiffInfo, 2, 2, applyEdits, createModifiedCellDiffInfo); + suite('Cell Movements', function () { - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - ]); + const keep = () => Promise.resolve(true); + const undo = () => Promise.resolve(true); + const diff = observableValue('cell1', nullDocumentDiff); + + ensureNoDisposablesAreLeakedInTestSuite(); + function createModifiedModel(id: string): ObservablePromise { + return `Modified:${id}` as any; + + } + function createOriginalModel(id: string): ObservablePromise { + return `Original:${id}` as any; + + } + test('Swap first two inserted cells in a previously empty notebook', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + } + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 0, length: 1, newIdx: 1 + }, cellsDiffInfo); + + assert.ok(result); + assert.strictEqual(result[1].length, 0); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Swap first two inserted cells in a notebook that had 2 cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 0, length: 1, newIdx: 1 + }, cellsDiffInfo); + + assert.ok(result); + assert.strictEqual(result[1].length, 0); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]); + }); + test('Move first inserted cell to the very bottom of notebook that had 2 cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 0, length: 1, newIdx: 3 + }, cellsDiffInfo); + + assert.ok(result); + assert.strictEqual(result[1].length, 0); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('3'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Move last cell to top of notebook after 2 cells were inserted', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 3, length: 1, newIdx: 0 + }, cellsDiffInfo); + + assert.ok(result); + assert.deepStrictEqual(result[1], [ + { + editType: CellEditType.Move, + index: 1, + length: 1, + newIdx: 0 + } + ]); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('3'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), + }, + ]); + }); + + test('Move second inserted cell to the very bottom of notebook that had 2 cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 1, length: 1, newIdx: 3 + }, cellsDiffInfo); + + assert.ok(result); + assert.strictEqual(result[1].length, 0); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('3'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Move second inserted cell to the second last position of notebook that had 2 cells', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 1, length: 1, newIdx: 2 + }, cellsDiffInfo); + + assert.ok(result); + assert.strictEqual(result[1].length, 0); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), + } + ]); + }); + test('Move first cell to the last position of notebook that had 3 cells deleted from the middle', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 0, length: 1, newIdx: 2 + }, cellsDiffInfo); + + assert.ok(result); + assert.deepStrictEqual(result[1], [ + { + editType: CellEditType.Move, + index: 0, + length: 1, + newIdx: 5 + } + ]); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 5, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('0'), + }, + ]); + }); + test('Move second cell to the last position of notebook that had 3 cells deleted from the middle', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), + }, + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 1, length: 1, newIdx: 2 + }, cellsDiffInfo); + + assert.ok(result); + assert.deepStrictEqual(result[1], [ + { + editType: CellEditType.Move, + index: 1, + length: 1, + newIdx: 5 + } + ]); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + + test('Move second cell to the last position of notebook that had 3 cells deleted from middle and 1 inserted in the middle', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), + }, + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 1, length: 1, newIdx: 3 + }, cellsDiffInfo); + + assert.ok(result); + assert.deepStrictEqual(result[1], [ + { + editType: CellEditType.Move, + index: 1, + length: 1, + newIdx: 5 + } + ]); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), + }, + ]); + }); + test('Move last cell to the second position of notebook that had 3 cells deleted from middle and 1 inserted in the middle', async function () { + const cellsDiffInfo: ICellDiffInfo[] = [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('New1'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), + }, + ]; + const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ + cells: [], kind: NotebookCellsChangeType.Move, + index: 3, length: 1, newIdx: 1 + }, cellsDiffInfo); + + assert.ok(result); + assert.deepStrictEqual(result[1], [ + { + editType: CellEditType.Move, + index: 5, + length: 1, + newIdx: 1 + } + ]); + assert.deepStrictEqual(result[0], [ + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, + modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 1, + modifiedCellIndex: 1, modifiedModel: createModifiedModel('5'), + }, + { + diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 2, + modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 3, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 4, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 5, + modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), + }, + { + diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, + modifiedCellIndex: 3, modifiedModel: createModifiedModel('New1'), + }, + ]); + }); }); - test('Delete a new cell from a notebook with 3 cells deleted', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 1, [ - // createICell(CellKind.Code, 'print("Hello World")') - ]], - cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); - - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), - }, - ]); - }); - test('Delete 2 cells from a notebook with 3 cells deleted', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), - }, - ]; - - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 2, [ - ]], - cellsDiffInfo, 4, 6, applyEdits, createModifiedCellDiffInfo); - - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 4, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - ]); - }); - test('Delete 3 cells from a notebook with 3 cells deleted', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'modified', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('6'), originalCellIndex: 6, - modifiedCellIndex: 4, modifiedModel: createModifiedModel('6'), - }, - ]; - - const result = adjustCellDiffAndOriginalModelBasedOnCellAddDelete([1, 3, [ - ]], - cellsDiffInfo, 5, 7, applyEdits, createModifiedCellDiffInfo); - - assert.deepStrictEqual(result, [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('6'), originalCellIndex: 4, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('6'), - }, - ]); - }); -}); - -suite('ChatEditingModifiedNotebookEntry Cell Movements', function () { - - const keep = () => Promise.resolve(true); - const undo = () => Promise.resolve(true); - const diff = observableValue('cell1', nullDocumentDiff); - - ensureNoDisposablesAreLeakedInTestSuite(); - function createModifiedModel(id: string): ObservablePromise { - return `Modified:${id}` as any; - - } - function createOriginalModel(id: string): ObservablePromise { - return `Original:${id}` as any; - - } - test('Swap first two inserted cells in a previously empty notebook', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - } - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 0, length: 1, newIdx: 1 - }, cellsDiffInfo); - - assert.ok(result); - assert.strictEqual(result[1].length, 0); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), - }, - ]); - }); - test('Swap first two inserted cells in a notebook that had 2 cells', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 0, length: 1, newIdx: 1 - }, cellsDiffInfo); - - assert.ok(result); - assert.strictEqual(result[1].length, 0); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]); - }); - test('Move first inserted cell to the very bottom of notebook that had 2 cells', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 0, length: 1, newIdx: 3 - }, cellsDiffInfo); - - assert.ok(result); - assert.strictEqual(result[1].length, 0); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('3'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('0'), - }, - ]); - }); - test('Move last cell to top of notebook after 2 cells were inserted', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 3, length: 1, newIdx: 0 - }, cellsDiffInfo); - - assert.ok(result); - assert.deepStrictEqual(result[1], [ - { - editType: CellEditType.Move, - index: 1, - length: 1, - newIdx: 0 - } - ]); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('3'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('2'), - }, - ]); - }); - - test('Move second inserted cell to the very bottom of notebook that had 2 cells', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 1, length: 1, newIdx: 3 - }, cellsDiffInfo); - - assert.ok(result); - assert.strictEqual(result[1].length, 0); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('3'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), - }, - ]); - }); - test('Move second inserted cell to the second last position of notebook that had 2 cells', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 1, length: 1, newIdx: 2 - }, cellsDiffInfo); - - assert.ok(result); - assert.strictEqual(result[1].length, 0); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('3'), - } - ]); - }); - test('Move first cell to the last position of notebook that had 3 cells deleted from the middle', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 0, length: 1, newIdx: 2 - }, cellsDiffInfo); - - assert.ok(result); - assert.deepStrictEqual(result[1], [ - { - editType: CellEditType.Move, - index: 0, - length: 1, - newIdx: 5 - } - ]); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 5, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('0'), - }, - ]); - }); - test('Move second cell to the last position of notebook that had 3 cells deleted from the middle', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('2'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 1, length: 1, newIdx: 2 - }, cellsDiffInfo); - - assert.ok(result); - assert.deepStrictEqual(result[1], [ - { - editType: CellEditType.Move, - index: 1, - length: 1, - newIdx: 5 - } - ]); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('2'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), - }, - ]); - }); - - test('Move second cell to the last position of notebook that had 3 cells deleted from middle and 1 inserted in the middle', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 1, length: 1, newIdx: 3 - }, cellsDiffInfo); - - assert.ok(result); - assert.deepStrictEqual(result[1], [ - { - editType: CellEditType.Move, - index: 1, - length: 1, - newIdx: 5 - } - ]); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 1, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 4, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('1'), - }, - ]); - }); - test('Move last cell to the second position of notebook that had 3 cells deleted from middle and 1 inserted in the middle', async function () { - const cellsDiffInfo: ICellDiffInfo[] = [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 2, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 4, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('New1'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 5, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('5'), - }, - ]; - const result = adjustCellDiffAndOriginalModelBasedOnCellMovements({ - cells: [], kind: NotebookCellsChangeType.Move, - index: 3, length: 1, newIdx: 1 - }, cellsDiffInfo); - - assert.ok(result); - assert.deepStrictEqual(result[1], [ - { - editType: CellEditType.Move, - index: 5, - length: 1, - newIdx: 1 - } - ]); - assert.deepStrictEqual(result[0], [ - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('0'), originalCellIndex: 0, - modifiedCellIndex: 0, modifiedModel: createModifiedModel('0'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('5'), originalCellIndex: 1, - modifiedCellIndex: 1, modifiedModel: createModifiedModel('5'), - }, - { - diff, keep, undo, type: 'unchanged', originalModel: createOriginalModel('1'), originalCellIndex: 2, - modifiedCellIndex: 2, modifiedModel: createModifiedModel('1'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('2'), originalCellIndex: 3, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('3'), originalCellIndex: 4, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'delete', originalModel: createOriginalModel('4'), originalCellIndex: 5, - modifiedCellIndex: undefined, modifiedModel: createModifiedModel('null'), - }, - { - diff, keep, undo, type: 'insert', originalModel: createOriginalModel('null'), originalCellIndex: undefined, - modifiedCellIndex: 3, modifiedModel: createModifiedModel('New1'), - }, - ]); - }); });