fix infinite loop when inserting more than 0xF000 lines at once

This commit is contained in:
nightwing 2014-11-20 23:01:53 +04:00
commit 27264bb9d9
2 changed files with 43 additions and 12 deletions

View file

@ -575,14 +575,14 @@ var Document = function(textOrLines) {
return; return;
if (isInsert && delta.lines.length > 0xF000) if (isInsert && delta.lines.length > 0xF000)
this.$splitAndapplyLargeDelta(delta); this.$splitAndapplyLargeDelta(delta, 0xF000);
// Apply. // Apply.
applyDelta(this.$lines, delta, doNotValidate); applyDelta(this.$lines, delta, doNotValidate);
this._signal("change", delta); this._signal("change", delta);
}; };
this.$splitAndapplyLargeDelta = function(delta) { this.$splitAndapplyLargeDelta = function(delta, MAX) {
// Split large insert deltas. This is necessary because: // Split large insert deltas. This is necessary because:
// 1. We need to support splicing delta lines into the document via $lines.splice.apply(...) // 1. We need to support splicing delta lines into the document via $lines.splice.apply(...)
// 2. fn.apply() doesn't work for a large number of params. The smallest threshold is on safari 0xFFFF. // 2. fn.apply() doesn't work for a large number of params. The smallest threshold is on safari 0xFFFF.
@ -592,18 +592,30 @@ var Document = function(textOrLines) {
// delta handling is too slow. If we make delete delta handling faster we can split all large deltas // delta handling is too slow. If we make delete delta handling faster we can split all large deltas
// as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js // as shown in https://gist.github.com/aldendaniels/8367109#file-document-snippet-js
// If we do this, update validateDelta() to limit the number of lines in a delete delta. // If we do this, update validateDelta() to limit the number of lines in a delete delta.
while (delta.lines.length > 0xF000) { var lines = delta.lines;
// Get split deltas. var l = lines.length;
var lines = delta.lines.splice(0, 0xF000); var row = delta.start.row;
lines.push(""); var column = delta.start.column;
var start = delta.start; var from = 0, to = 0;
do {
from = to;
to += MAX - 1;
var chunk = lines.slice(from, to);
if (to > l) {
// Update remaining delta.
delta.lines = chunk;
delta.start.row = row + from;
delta.start.column = column;
break;
}
chunk.push("");
this.applyDelta({ this.applyDelta({
start: this.pos(start.row, start.column), start: this.pos(row + from, column),
end: this.pos(start.row += 0xF000, start.column = 0), // Updates remaining delta. end: this.pos(row + to, column = 0),
action: delta.action, action: delta.action,
lines: lines lines: chunk
}, true); }, true);
} } while(true);
}; };
/** /**
@ -615,7 +627,7 @@ var Document = function(textOrLines) {
this.applyDelta({ this.applyDelta({
start: range.start, start: range.start,
end: range.end, end: range.end,
action: delta.action == "insert" ? "remove" : "insert", action: (delta.action == "insert" ? "remove" : "insert"),
lines: delta.lines.slice() lines: delta.lines.slice()
}); });
}; };

View file

@ -296,6 +296,25 @@ module.exports = {
"test: empty document has to contain one line": function() { "test: empty document has to contain one line": function() {
var doc = new Document(""); var doc = new Document("");
assert.equal(doc.$lines.length, 1); assert.equal(doc.$lines.length, 1);
},
"test: inserting huge delta": function() {
var doc = new Document("");
var val = "";
var MAX = 0xF000;
for (var i = 0; i < 10 * MAX; i++) {
val += i + "\n"
}
doc.setValue(val);
assert.equal(doc.getValue(), val);
for (var i = 3 * MAX + 2; i >= 3 * MAX - 2; i--) {
val = doc.getLines(0, i).join("\n");
doc.setValue("\nab");
assert.equal(doc.getValue(), "\nab");
doc.insert({row: 1, column: 1}, val);
assert.equal(doc.getValue(), "\na" + val + "b");
}
} }
}; };