fix output edit sequence.
This commit is contained in:
parent
25d716f900
commit
27388ab7cf
3 changed files with 114 additions and 17 deletions
|
@ -3,6 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { flatten } from 'vs/base/common/arrays';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
|
@ -358,6 +359,14 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
}
|
||||
|
||||
private _doApplyEdits(rawEdits: ICellEditOperation[], synchronous: boolean, computeUndoRedo: boolean = true): void {
|
||||
type TransformedEdit = {
|
||||
edit: ICellEditOperation;
|
||||
cellIndex: number;
|
||||
end: number | undefined;
|
||||
originalIndex: number;
|
||||
};
|
||||
|
||||
// compress all edits which have no side effects on cell index
|
||||
const edits = rawEdits.map((edit, index) => {
|
||||
let cellIndex: number = -1;
|
||||
if ('index' in edit) {
|
||||
|
@ -372,7 +381,6 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
throw new Error('Invalid cell edit');
|
||||
}
|
||||
|
||||
const cell = this._cells[cellIndex];
|
||||
return {
|
||||
edit,
|
||||
cellIndex,
|
||||
|
@ -380,8 +388,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
(edit.editType === CellEditType.DocumentMetadata)
|
||||
? undefined
|
||||
: (edit.editType === CellEditType.Replace ? edit.index + edit.count : cellIndex),
|
||||
originalIndex: index,
|
||||
originalCellOutputsLength: cell?.outputs.length ?? 0
|
||||
originalIndex: index
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
if (a.end === undefined) {
|
||||
|
@ -393,9 +400,40 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
}
|
||||
|
||||
return b.end - a.end || b.originalIndex - a.originalIndex;
|
||||
}).reduce((prev, curr) => {
|
||||
if (!prev.length) {
|
||||
// empty
|
||||
prev.push([curr]);
|
||||
} else {
|
||||
const last = prev[prev.length - 1];
|
||||
const index = last[0].cellIndex;
|
||||
|
||||
if (curr.cellIndex === index) {
|
||||
last.push(curr);
|
||||
} else {
|
||||
prev.push([curr]);
|
||||
}
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, [] as TransformedEdit[][]).map(editsOnSameIndex => {
|
||||
const replaceEdits: TransformedEdit[] = [];
|
||||
const otherEdits: TransformedEdit[] = [];
|
||||
|
||||
editsOnSameIndex.forEach(edit => {
|
||||
if (edit.edit.editType === CellEditType.Replace) {
|
||||
replaceEdits.push(edit);
|
||||
} else {
|
||||
otherEdits.push(edit);
|
||||
}
|
||||
});
|
||||
|
||||
return [...otherEdits.reverse(), ...replaceEdits];
|
||||
});
|
||||
|
||||
for (const { edit, cellIndex, originalCellOutputsLength } of edits) {
|
||||
const flattenEdits = flatten(edits);
|
||||
|
||||
for (const { edit, cellIndex } of flattenEdits) {
|
||||
switch (edit.editType) {
|
||||
case CellEditType.Replace:
|
||||
this._replaceCells(edit.index, edit.count, edit.cells, synchronous, computeUndoRedo);
|
||||
|
@ -404,7 +442,7 @@ export class NotebookTextModel extends Disposable implements INotebookTextModel
|
|||
this._assertIndex(cellIndex);
|
||||
const cell = this._cells[cellIndex];
|
||||
if (edit.append) {
|
||||
this._spliceNotebookCellOutputs(cell, [[originalCellOutputsLength, 0, edit.outputs.map(op => new NotebookCellOutputTextModel(op))]], computeUndoRedo);
|
||||
this._spliceNotebookCellOutputs(cell, [[cell.outputs.length, 0, edit.outputs.map(op => new NotebookCellOutputTextModel(op))]], computeUndoRedo);
|
||||
} else {
|
||||
this._spliceNotebookCellOutputs2(cell, edit.outputs.map(op => new NotebookCellOutputTextModel(op)), computeUndoRedo);
|
||||
}
|
||||
|
|
|
@ -350,12 +350,9 @@ export const enum CellEditType {
|
|||
Metadata = 3,
|
||||
CellLanguage = 4,
|
||||
DocumentMetadata = 5,
|
||||
OutputsSplice = 6,
|
||||
Move = 7,
|
||||
Unknown = 8,
|
||||
CellContent = 9,
|
||||
OutputItems = 10,
|
||||
PartialMetadata = 11
|
||||
Move = 6,
|
||||
OutputItems = 7,
|
||||
PartialMetadata = 8
|
||||
}
|
||||
|
||||
export interface ICellDto2 {
|
||||
|
|
|
@ -98,7 +98,6 @@ suite('NotebookTextModel', () => {
|
|||
{ editType: CellEditType.Replace, index: 1, count: 1, cells: [] },
|
||||
{ editType: CellEditType.Replace, index: 3, count: 0, cells: [new TestCell(viewModel.viewType, 5, 'var e = 5;', 'javascript', CellKind.Code, [], modeService)] },
|
||||
], true, undefined, () => undefined, undefined);
|
||||
|
||||
assert.strictEqual(textModel.cells.length, 4);
|
||||
|
||||
assert.strictEqual(textModel.cells[0].getValue(), 'var a = 1;');
|
||||
|
@ -563,11 +562,6 @@ suite('NotebookTextModel', () => {
|
|||
});
|
||||
|
||||
test('Destructive sorting in _doApplyEdits #121994', async function () {
|
||||
|
||||
if (1) {
|
||||
this.skip();
|
||||
}
|
||||
|
||||
await withTestNotebook([
|
||||
['var a = 1;', 'javascript', CellKind.Code, [{ outputId: 'i42', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}]
|
||||
], async (editor) => {
|
||||
|
@ -596,4 +590,72 @@ suite('NotebookTextModel', () => {
|
|||
assert.strictEqual(notebook.cells[0].outputs[0].outputs.length, 2);
|
||||
});
|
||||
});
|
||||
|
||||
test('Destructive sorting in _doApplyEdits #121994. cell splice between output changes', async function () {
|
||||
await withTestNotebook([
|
||||
['var a = 1;', 'javascript', CellKind.Code, [{ outputId: 'i42', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}],
|
||||
['var b = 2;', 'javascript', CellKind.Code, [{ outputId: 'i43', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}],
|
||||
['var c = 3;', 'javascript', CellKind.Code, [{ outputId: 'i44', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}]
|
||||
], async (editor) => {
|
||||
const notebook = editor.viewModel.notebookDocument;
|
||||
|
||||
const edits: ICellEditOperation[] = [
|
||||
{
|
||||
editType: CellEditType.Output, index: 0, outputs: []
|
||||
},
|
||||
{
|
||||
editType: CellEditType.Replace, index: 1, count: 1, cells: []
|
||||
},
|
||||
{
|
||||
editType: CellEditType.Output, index: 2, append: true, outputs: [{
|
||||
outputId: 'newOutput',
|
||||
outputs: [{ mime: 'text/plain', value: 'cba' }, { mime: 'application/foo', value: 'cba' }]
|
||||
}]
|
||||
}
|
||||
];
|
||||
|
||||
editor.viewModel.notebookDocument.applyEdits(edits, true, undefined, () => undefined, undefined);
|
||||
|
||||
assert.strictEqual(notebook.cells.length, 2);
|
||||
assert.strictEqual(notebook.cells[0].outputs.length, 0);
|
||||
assert.strictEqual(notebook.cells[1].outputs.length, 2);
|
||||
assert.strictEqual(notebook.cells[1].outputs[0].outputId, 'i44');
|
||||
assert.strictEqual(notebook.cells[1].outputs[1].outputId, 'newOutput');
|
||||
});
|
||||
});
|
||||
|
||||
test('Destructive sorting in _doApplyEdits #121994. cell splice between output changes 2', async function () {
|
||||
await withTestNotebook([
|
||||
['var a = 1;', 'javascript', CellKind.Code, [{ outputId: 'i42', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}],
|
||||
['var b = 2;', 'javascript', CellKind.Code, [{ outputId: 'i43', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}],
|
||||
['var c = 3;', 'javascript', CellKind.Code, [{ outputId: 'i44', outputs: [{ mime: 'm/ime', value: 'test' }] }], {}]
|
||||
], async (editor) => {
|
||||
const notebook = editor.viewModel.notebookDocument;
|
||||
|
||||
const edits: ICellEditOperation[] = [
|
||||
{
|
||||
editType: CellEditType.Output, index: 1, append: true, outputs: [{
|
||||
outputId: 'newOutput',
|
||||
outputs: [{ mime: 'text/plain', value: 'cba' }, { mime: 'application/foo', value: 'cba' }]
|
||||
}]
|
||||
},
|
||||
{
|
||||
editType: CellEditType.Replace, index: 1, count: 1, cells: []
|
||||
},
|
||||
{
|
||||
editType: CellEditType.Output, index: 1, append: true, outputs: [{
|
||||
outputId: 'newOutput2',
|
||||
outputs: [{ mime: 'text/plain', value: 'cba' }, { mime: 'application/foo', value: 'cba' }]
|
||||
}]
|
||||
}
|
||||
];
|
||||
|
||||
editor.viewModel.notebookDocument.applyEdits(edits, true, undefined, () => undefined, undefined);
|
||||
|
||||
assert.strictEqual(notebook.cells.length, 2);
|
||||
assert.strictEqual(notebook.cells[0].outputs.length, 1);
|
||||
assert.strictEqual(notebook.cells[1].outputs.length, 1);
|
||||
assert.strictEqual(notebook.cells[1].outputs[0].outputId, 'i44');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue