提交 7296da24 编写于 作者: A Alex Dima

Reimplement EditableTextModel._applyEdits

上级 92223424
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import assert = require('assert');
import {Range} from 'vs/editor/common/core/range';
import Position = require('vs/editor/common/core/position');
import EditorCommon = require('vs/editor/common/editorCommon');
import {EditableTextModel, IValidatedEditOperation} from 'vs/editor/common/model/editableTextModel';
import {TextModel} from 'vs/editor/common/model/textModel';
import {LineMarker, TextModelWithMarkers} from 'vs/editor/common/model/textModelWithMarkers';
import {ILineMarker} from 'vs/editor/common/model/modelLine';
import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2';
import {MirrorModel, IMirrorModelEvents} from 'vs/editor/common/model/mirrorModel';
import {assertSyncedModels, testApplyEditsWithSyncedModels} from 'vs/editor/test/common/model/editableTextModelTestUtils';
const GENERATE_TESTS = false;
suite('EditorModel Auto Tests', () => {
function editOp(startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, text:string[]): EditorCommon.IIdentifiedSingleEditOperation {
return {
identifier: null,
range: new Range(startLineNumber, startColumn, endLineNumber, endColumn),
text: text.join('\n'),
forceMoveMarkers: false
};
}
test('auto1', () => {
testApplyEditsWithSyncedModels(
[
"ioe",
"",
"yjct",
"",
"",
],
[
editOp(1, 2, 1, 2, ["b", "r", "fq"]),
editOp(1, 4, 2, 1, ["", ""]),
],
[
"ib",
"r",
"fqoe",
"",
"yjct",
"",
"",
]
);
});
test('auto2', () => {
testApplyEditsWithSyncedModels(
[
"f",
"littnhskrq",
"utxvsizqnk",
"lslqz",
"jxn",
"gmm",
],
[
editOp(1, 2, 1, 2, ["", "o"]),
editOp(2, 4, 2, 4, ["zaq", "avb"]),
editOp(2, 5, 6, 2, ["jlr", "zl", "j"]),
],
[
"f",
"o",
"litzaq",
"avbtjlr",
"zl",
"jmm",
]
);
});
test('auto3', () => {
testApplyEditsWithSyncedModels(
[
"ofw",
"qsxmziuvzw",
"rp",
"qsnymek",
"elth",
"wmgzbwudxz",
"iwsdkndh",
"bujlbwb",
"asuouxfv",
"xuccnb",
],
[
editOp(4, 3, 4, 3, [""]),
],
[
"ofw",
"qsxmziuvzw",
"rp",
"qsnymek",
"elth",
"wmgzbwudxz",
"iwsdkndh",
"bujlbwb",
"asuouxfv",
"xuccnb",
]
);
});
});
function getRandomInt(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getRandomString(minLength: number, maxLength: number): string {
let length = getRandomInt(minLength, maxLength);
let r = '';
for (let i = 0; i < length; i++) {
r += String.fromCharCode(getRandomInt('a'.charCodeAt(0), 'z'.charCodeAt(0)));
}
return r;
}
function generateFile(small:boolean): string {
let lineCount = getRandomInt(1, small ? 3 : 10);
let lines: string[] = [];
for (let i = 0; i < lineCount; i++) {
lines.push(getRandomString(0, small ? 3 : 10));
}
return lines.join('\n');
}
function generateEdits(content:string): ITestModelEdit[] {
let result:ITestModelEdit[] = [];
let cnt = getRandomInt(1, 5);
let maxOffset = content.length;
while (cnt > 0 && maxOffset > 0) {
let offset = getRandomInt(0, maxOffset);
let length = getRandomInt(0, maxOffset - offset);
result.push({
offset: offset,
length: length,
text: generateFile(true)
});
maxOffset = offset - 1;
cnt--;
}
result.reverse();
return result;
}
interface ITestModelEdit {
offset: number;
length: number;
text: string;
}
class TestModel {
public initialContent: string;
public resultingContent: string;
public edits: EditorCommon.IIdentifiedSingleEditOperation[];
constructor() {
this.initialContent = generateFile(false);
let edits = generateEdits(this.initialContent);
let currentEditIdx = 0;
let lineNumber = 1;
let column = 1;
let editStartPosition: Position.Position = null;
this.edits = [];
for (let offset = 0, len = this.initialContent.length; currentEditIdx < edits.length && offset <= len; offset++) {
let ch = this.initialContent.charAt(offset);
if (!editStartPosition) {
if (offset === edits[currentEditIdx].offset) {
editStartPosition = new Position.Position(lineNumber, column);
}
}
if (editStartPosition) {
if (offset === edits[currentEditIdx].offset + edits[currentEditIdx].length) {
this.edits.push({
identifier: null,
range: new Range(editStartPosition.lineNumber, editStartPosition.column, lineNumber, column),
text: edits[currentEditIdx].text,
forceMoveMarkers: false
});
currentEditIdx++;
editStartPosition = null;
}
}
if (ch === '\n') {
lineNumber++;
column = 1;
} else {
column++;
}
}
this.resultingContent = this.initialContent;
for (let i = edits.length - 1; i >= 0; i--) {
this.resultingContent = (
this.resultingContent.substring(0, edits[i].offset) +
edits[i].text +
this.resultingContent.substring(edits[i].offset + edits[i].length)
);
}
}
public print(): string {
let r: string[] = [];
r.push('testApplyEditsWithSyncedModels(');
r.push('\t[');
let initialLines = this.initialContent.split('\n');
r = r.concat(initialLines.map((i) => `\t\t"${i}",`));
r.push('\t],');
r.push('\t[');
r = r.concat(this.edits.map((i) => {
let text = `["` + i.text.split('\n').join(`", "`) + `"]`;
return `\t\teditOp(${i.range.startLineNumber}, ${i.range.startColumn}, ${i.range.endLineNumber}, ${i.range.endColumn}, ${text}),`;
}));
r.push('\t],');
r.push('\t[');
let resultLines = this.resultingContent.split('\n');
r = r.concat(resultLines.map((i) => `\t\t"${i}",`));
r.push('\t]');
r.push(');');
return r.join('\n');
}
}
if (GENERATE_TESTS) {
let number = 1;
while(true) {
console.log('------BEGIN NEW TEST: ' + number);
let testModel = new TestModel();
console.log(testModel.print());
console.log('------END NEW TEST: ' + (number++));
try {
testApplyEditsWithSyncedModels(
testModel.initialContent.split('\n'),
testModel.edits,
testModel.resultingContent.split('\n')
);
// throw new Error('a');
} catch(err) {
console.log('bubu');
console.log(testModel.print());
break;
}
// break;
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import assert = require('assert');
import EditorCommon = require('vs/editor/common/editorCommon');
import {EditableTextModel, IValidatedEditOperation} from 'vs/editor/common/model/editableTextModel';
import {TextModel} from 'vs/editor/common/model/textModel';
import {MirrorModel2} from 'vs/editor/common/model/mirrorModel2';
import {MirrorModel, IMirrorModelEvents} from 'vs/editor/common/model/mirrorModel';
export function testApplyEditsWithSyncedModels(original:string[], edits:EditorCommon.IIdentifiedSingleEditOperation[], expected:string[]): void {
var originalStr = original.join('\n');
var expectedStr = expected.join('\n');
assertSyncedModels(originalStr, (model, assertMirrorModels) => {
// Apply edits & collect inverse edits
var inverseEdits = model.applyEdits(edits);
// Assert edits produced expected result
assert.deepEqual(model.getValue(EditorCommon.EndOfLinePreference.LF), expectedStr);
assertMirrorModels();
// Apply the inverse edits
var inverseInverseEdits = model.applyEdits(inverseEdits);
// Assert the inverse edits brought back model to original state
assert.deepEqual(model.getValue(EditorCommon.EndOfLinePreference.LF), originalStr);
// Assert the inverse of the inverse edits are the original edits
assert.deepEqual(inverseInverseEdits, edits);
assertMirrorModels();
});
}
export function assertSyncedModels(text:string, callback:(model:EditableTextModel, assertMirrorModels:()=>void)=>void, setup:(model:EditableTextModel)=>void = null): void {
var model = new EditableTextModel([], TextModel.toRawText(text), null);
model.setEOL(EditorCommon.EndOfLineSequence.LF);
if (setup) {
setup(model);
}
var mirrorModel1 = new MirrorModel(null, model.getVersionId(), model.toRawText(), null);
var mirrorModel1PrevVersionId = model.getVersionId();
var mirrorModel2 = new MirrorModel2(null, model.toRawText().lines, model.toRawText().EOL, model.getVersionId());
var mirrorModel2PrevVersionId = model.getVersionId();
model.addListener(EditorCommon.EventType.ModelContentChanged, (e:EditorCommon.IModelContentChangedEvent) => {
let versionId = e.versionId;
if (versionId < mirrorModel1PrevVersionId) {
console.warn('Model version id did not advance between edits (1)');
}
mirrorModel1PrevVersionId = versionId;
let mirrorModelEvents:IMirrorModelEvents = {
propertiesChanged: null,
contentChanged: [e]
};
mirrorModel1.onEvents(mirrorModelEvents);
});
model.addListener(EditorCommon.EventType.ModelContentChanged2, (e:EditorCommon.IModelContentChangedEvent2) => {
let versionId = e.versionId;
if (versionId < mirrorModel2PrevVersionId) {
console.warn('Model version id did not advance between edits (2)');
}
mirrorModel2PrevVersionId = versionId;
mirrorModel2.onEvents([e]);
});
var assertMirrorModels = () => {
model._assertLineNumbersOK();
assert.equal(mirrorModel2.getText(), model.getValue(), 'mirror model 2 text OK');
assert.equal(mirrorModel2.version, model.getVersionId(), 'mirror model 2 version OK');
assert.equal(mirrorModel1.getValue(), model.getValue(), 'mirror model 1 text OK');
assert.equal(mirrorModel1.getVersionId(), model.getVersionId(), 'mirror model 1 version OK');
};
callback(model, assertMirrorModels);
model.dispose();
mirrorModel1.dispose();
mirrorModel2.dispose();
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册